reactjs / rfcs

RFCs for changes to React

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Why not make returning "undefined" bail out of component re-render?

ruifortes opened this issue · comments

I may be missing something obvious but I still can't understand why the following is a bad idea
(maybe someone already explained it to me but... I'm not only slightly dumb but also very forgetful)

There's been discussion about how to implement some kind of "selector" in useContext and workaround methods using React.memo and I think canceling component re-render by returning undefined could be a simple solution.
Even in components that don't useContext could benefit by simplifying some memoization hedge cases.

I've been using a HOC that simply returns the last wrapped component render value if it returns undefined but unfortunately "react@experimental" now forces that "all" hooks be called and that completely invalidates this all bailout system.

Why not allow for components that return before all hooks are called as long has they're called in the right order? (and of course...implement the "cancel on undefined" natively)

Then using a simple hook like this:

function useSomeChanged (...values) {
  let ref = useRef(values)
  let changed = ref.current.some(
    (lastValue, i) => lastValue !== values[i]
  )
  ref.current = values
  return changed
}

one could:

function MyComponent(props) {
  const {someContextProp} = useContext(GlobalStoreContext)
  let shouldRender = useSomeChanged(props, someContextProp)

  if(!shouldRender) return

 (...do all rendering stuff)

}

Calling the component function (that would return early) should be more worst the calling some selector function.
Also, is that changeBits thingy really such a performance boost over some shallow comparison?

One thing I remember being told is that returning undefined is kind of "ugly" but... couldn't really understand why.

With this you don't need a context selector nor even a React.memo HOC

Would someone tell me what's the catch with this approach?

Thanks

...just an example where useMemo gets a little annoying.
Imagine a table component that get's it's field names from the actual data. (assuming homogeneous data here)

The Header part would only exist if there is data to show and would be defined in a useMemo depending only on "data" I would have to include conditionals for when the data is empty.

In a case where data of the same type is added to the list it could be optimized the only depending on data[0]...but then you need to ensure data is always an array, and you lose some semantics for when data is undefined and have a conditional for undefined in the useMemo function.

It would be nice to just return a "Loading" or "NoData" components if data is undefined or empty respectively

Returning undefined has already the meaning of "do no render anything for now".
This would be a breaking change, again affecting hundreds of thousand react developers and applications.
If you want to suggest something like this, maybe discussing something like return React.BailOut or something might be worth a try (though I guess it has already been discusses plenty), but I don't think a breaking change will have any chance.

Yes, I already posted about it a long time ago in the thread [Provide more ways to bail out inside Hooks · Issue #14110 · facebook/react]((No Title)) but the responses were not very helpful:

@ruifortes : I don't think return undefined would be selected as the approach, because it's too likely that someone might accidentally not return anything from their component (which also returns undefined). Goodness knows I've made that mistake myself.

@ruifortes: Personally I wouldn't be to happy to give undefined as return value such an important meaning. Also returning something from render to mark "bail out", wouldn't allow customHooks to "bail out". As explained above I'd rather be able to write simple customHooks, which will only cause needed rerenders.

This would not be a breaking change. You "cannot" return undefined from the render function.
To "not" render the component you have to return null and also I'm not talking about bailing out inside hooks.

I don't understand the willingness to not use the different semantics.
What's wrong the returning undefined meaning "I'm not stating anything about this component,
leave has is"

Please try to provide more useful responses

Thanks

And by the way... react@experimental throwing when "not calling all hooks" is breaking thing for me right now and none of my proposals do

This was enforced by https://reactjs.org/docs/hooks-rules.html#eslint-plugin all along, for good reason.

Once again, I understand that "React relies on the order in which Hooks are called"!!
The question is why "all of them need to be called"

well...just to keep this open facebook/react#17446 (comment)

commented

Hi, thanks for your suggestion. RFCs should be submitted as pull requests, not issues. I will close this issue but feel free to resubmit in the PR format.