Bug: Method from React Context can't read its own state.

2
closed
eakl
eakl
Posted 1 month ago

Bug: Method from React Context can't read its own state. #22549

React version: 17.0.2

Steps To Reproduce

  1. Open the Code Sandbox and the Console
  2. Click on Open. You will see the following console.logs (1. the modal opens, 2. the config input that is passed contains data and 2 callbacks, 3. the config is set in the state)
  3. Close the modal with the X button or with Cancel (you will see the following console.logs (1. the modal closes, 2. the dialogConfig state is empty)
  4. Reproduce steps 1 to 4, you will see that the dialogConfig state is not empty.
  5. Open the React Dev Tools and click on Context.Provider to see that the dialogConfig object is always updated when the modal opens but not always cleared when the modal closes

Here is the code sandbox with different modal dependencies but same issue:

The current behavior

When onOpenDialog is called, the dialogConfig state is updated every time but onCloseDialog see it as empty half the time and the condition doesn't pass

const onCloseDialog = () => {
    console.log("-- Close Dialog");
    setDialogMode("");
    console.log("-- dialogConfig State: ", dialogConfig); // This is empty half the time
    if (Object.keys(dialogConfig).length > 0) {
      console.log("-- Reset dialogConfig");
      setDialogConfig({});
    }
  };

The expected behavior

When onCloseDialog is called, it should always read the state as non empty object

ChamsBouzaiene
ChamsBouzaiene
Created 1 month ago

@eakl first of all this is not a react bug it's a common problem that us devs stumble upon some time the issue here is with the function closures you are accessing dialogConfig state in the onCloseDialog your code assume that the function setDialogConfig is sync and also that the function is in the right scope but it's not it's bound to the previous closure when the function was created so to mitgate this issue when you have trouble with your function closure you can access your state like this :

 const onCloseDialog = () => {
    console.log("-- Close Dialog");
    setDialogMode(false);
    console.log("-- dialogConfig State: ", dialogConfig, dialogMode);
    setDialogConfig((prevConfig) => {
      if (Object.keys(prevConfig).length > 0) {
        console.log("-- Reset dialogConfig");
        return {};
      }
    });
  };

using the setDialogConfig callback you are sure that you are accessing the right state object without worring about the closures

another thing i would recommend that you drop the way you are passing the onCloseDialog and onSubmit function callbacks to the dialogConfig cause in that way you are adding an unnecessary step by adding function callbacks to state that are accessible via the context already instead directly pass them to the modal the consumer

I also invite you to read this article from dan about react hooks and closures check demo here

eakl
eakl
Created 1 month ago

@ChamsBouzaiene Thank you for the clear explanation and the reading material. I didn't know this was a known problem but it makes sense. I also appreciate your recommendation to simplify my code.