0

I've been using React Hook with useSelector and useDispatch for a while, mostly it works very well but recently I've experienced some very wired scenario. For example

// parentComponent
const MyComponent = (props) => {
  const hasChanged = useSelector(state => {
    const isChanged = checkIfChanged(state);
    console.log('useSelector isChanged:>> ', isChanged);
    return isChanged;
  });

  const selectChange = async(userId, userCode)=> {
    console.log('selectChange hasChanged :>> ', hasChanged);
    // ...
  }
  return (
      <div>
        <ChildComponent onSelectChange={selectChange} />
      </div>
  );
}

I have my properties saved in the state and whenever there is anything changed in my component, my hasChanged from useSelector will become true, however, when I made a change, I can see my hasChanged already become true in the useSelector, but still false inside my function selectChange!

console log
useSelector isChanged:>> true
useSelector isChanged:>> true
selectChange hasChanged :>> false // why it's false here as already true from useSelector
useSelector isChanged:>> true

Does anyone have the same experience? I am wondering if it's because my selectChanged is async-await so the value inside will not fetch from the latest state?

Drex
  • 3,346
  • 9
  • 33
  • 58
  • I think it's one of [zalgo being released](https://blog.izs.me/2013/08/designing-apis-for-asynchrony/) cases. If you think, `selectChange` is async, so it will return instantly and program will move on, in true `async` fashion. But the rest of the program is sync! You can't casually mix up sync and async — consider every single function and match the "cadence" of sync-ones to async-ones. Also, to enable caching, `useSelector` function has to be declared outside the component declaration, see https://react-redux.js.org/api/hooks#using-memoizing-selectors – revelt Jun 13 '22 at 10:02

1 Answers1

0

I think you should use useEffect();

const {userId, userCode} = useSelector(state => { /* ... */ });
const selectChange = async () => {
    if (hasChanged) {
      await dispatch(notifyUser(userId, userCode));
    } else {
      await dispatch(redirectPage(userCode));
    }
}

useEffect(() => {
    selectChange();
}, [hasChanged]); 
return (
   <div>
       <Select />
   </div>
);
Ryuko
  • 377
  • 1
  • 13
  • Well, that might not work because my `selectChange(userId, userCode)` is actually a callback from my my child component, which it would set the input parameter there... – Drex Jul 31 '20 at 02:05
  • 1
    I think you should store the input variables in the global state. – Ryuko Jul 31 '20 at 02:22
  • did you figure it out? I'm facing the same issue! – tschleuss Aug 25 '20 at 04:28