Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't get latest Redux store entity after dispatch, inside callback. #33

Open
sanjarcode opened this issue Mar 16, 2023 · 5 comments
Open
Assignees

Comments

@sanjarcode
Copy link
Member

sanjarcode commented Mar 16, 2023

Situation + Problem

The following code doesn't work.

const dispatch = useDispatch();

const paymentForm = useSelector(myPaymentFormSelector);

const submitHandler = () => {
  dispatch(someLastThing()); // which will change "paymentFormSelector" entity in store

  paymentForm; // not the latest value, since it's pointing to a closured value

  removeMyFormFromView();
}

Observations:

  • Technically, this is a JS detail, not something Redux specific.
  • It's a React problem, more than a Redux problem - rules of hook. can't use them inside a callback (since hooks can be called in components, and that too at the first level).

Redux:

  • What Redux/RTK lacks is a way to add the callback logic that uses latest store, after dispatch.

Workaround ('solution')

Use useEffect, with a boolean state (useState), and move the logic after 'dispatch' in the useEffect.

Code:

const dispatch = useDispatch();
const [done, setDone] = useState(false);

const paymentForm = useSelector(myPaymentFormSelector);

const submitHandler = () => {
    dispatch(someLastThing());
   // which will change "paymentFormSelector" entity in store
}

useEffect(() => {
  if(done) {
    paymentForm; // OK

    removeMyFormFromView();
  }
}, [done]);
@sanjarcode sanjarcode self-assigned this Mar 16, 2023
@sanjarcode
Copy link
Member Author

@sanjarcode
Copy link
Member Author

sanjarcode commented Mar 16, 2023

Observation: It's quite crazy to code like this.

  1. The boolean state I'm using will of course retain state if the callback doesn't cause the component to unmount. Work-around: set the boolean to false, from inside the useEffect (inside the conditional).
  2. The callback may use component's state (of the current render), normal variables, props, which may change on the next render (after which the useEffect will run). Work-around (potentially unscalable/inefficient): create a larger state (than a mere boolean), and pass entities used by "after dispatch" logic in this larger state, so they can be used without worrying about updates. If this is not possible (due to references, use structuredClone).

@sanjarcode
Copy link
Member Author

sanjarcode commented Mar 16, 2023

Todo:

  • how to get around this, a Redux plugin, some other state management library, some generalizable JS hack/gymnastic? Idk.
  • In the worst case (at the sake of synchrony), have dispatch return a promise after which the logic can be run.
  • Or, maybe, the patterns I'm using in React is causing this issue, changing them could avoid such situations altogether.

@sanjarcode sanjarcode changed the title Can't get latest store after dispatch, inside callback. Can't get latest Redux store entity after dispatch, inside callback. Mar 16, 2023
@atultiwaree
Copy link

atultiwaree commented Sep 26, 2023

Hi! @sanjarcode I'm also facing same issue pasting below code

  var lastMessageId = chatThreadFromCache?.messages[chatThreadFromCache?.messages?.length - 1]?._id

  function fetchFreshLatestChats(token, chatRoomId) {

    trigger({ token, chatRoomId, _id :  lastMessageId }, false)

      .then(responseLatestMessage => {

        dispatch(toggleNewMessageRecieved())
    
        if (responseLatestMessage?.data?.messages?.length > 0) {
    
          // console.log(responseLatestMessage?.messages[0]._id,  chatThreadFromCache?.messages.at(-1)?._id)
            
          if (responseLatestMessage?.data?.messages[0]._id !== lastMessageId) {
    
            dispatch(updateThread({ chatRoomId, newMessage: responseLatestMessage?.data?.messages}));
          
          } else console.log("Encountered same.")
    
          
        } else {
    
    
        }

        setSeenToServer({ token, roomId: chatRoomId })
      
      }).catch(e => console.log("Error While fetching latest message", e))
}

  
  useEffect(() => {

    if (newMessageStatus === true) {
      fetchFreshLatestChats(token, chatRoomId)
    } else {
      console.log("")
    }

  }, [newMessageStatus] ); 

In the above code what I'm doing basically passing last chat message Id, and getting latest chat

but issue is that sometimes I get the same last chat id and hence I get repeated message please suggest me solution I'm very new to react-redux

@sanjarcode
Copy link
Member Author

sanjarcode commented Oct 1, 2023

you don't have a redux problem, since you check !== lastMessageId before changing the store updateThread.

In my case I change the store, but still want to work with the changed data. That is different.


Try to replace !== lastMessageId with != lastMessageId. Maybe you're trying to match string with number strictly. Example: 2 and '2''. This funny thing happened to be once

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants