Benjamin Furlani
Benjamin Furlani

Reputation: 120

Updating State Through props with hooks

I am trying to update the state of something on a click from a component by lifting up the state and passing it as a prop into the other component and trying to update it.

this is the App.js

function App() {
  const [currentConfig, setCurrentConfig] = useState(0);
  const availableConfigs = [
    { id: 1, name: "Config 1", number: 1, key: 1 },
    { id: 2, name: "Config 2", number: 2, key: 2 },
    { id: 3, name: "Config 3", key: 3 },
    { id: 4, name: "Config 4", key: 4 },
    { id: 5, name: "Config 5", key: 5 },
    { id: 6, name: "Config 6", key: 6 },
    { id: 7, name: "Config 7", key: 7 },
  ];

  const [configs, setConfigs] = useState(availableConfigs);

  //function undoConfigAnimation(currentConfig) {}

  return (
    <div>
      <Tree
        configs={configs}
        animateConfigs={startConfigAnimation}
        setConfig={setCurrentConfig}
        currentConfig={currentConfig}
      />
      <NavBar />
    </div>
  );

  function startConfigAnimation(configClicked) {
    console.log(currentConfig);
    configs.forEach((config) => {
      if (configClicked !== config.name) {
        var elm = document.getElementById(config.name);
        elm.style.transform = "translate(-200px)";
        setTimeout(() => (elm.style.transform = "rotateZ(180deg)"), 1000);
      }
    });
  }
}

export default App;

this is the component

function Tree(props) {
  return (
    <div class="treeContainer">
      {props.configs.map((config) => {
        return (
          <div
            id={config.name}
            class="container1"
            onClick={() => {
              props.setConfig(config.name);

              props.animateConfigs(config.name);
              if (props.currentConfig !== config.name) {
                props.setConfig.bind(config.name);
              }
            }}
          >
            <Configs configNumber={config.number} configName={config.name} />
          </div>
        );
      })}
    </div>
  );
}
export default Tree;

currently, it does update the state, but it only updates it to the state before the click so an example output if the currentConfig === 0 would be as follows

click config 1 currentConfig = 0 click config 2 currentConfig = "config 1"

Upvotes: 0

Views: 63

Answers (1)

Domino987
Domino987

Reputation: 8804

Since the setState is async, the console.log will always be one behind. This does not mean that the state is not updated, but only not displayed in the console or yet available in the function.

So the flow would be:

  1. You dispatch the change.
  2. You call startConfigAnimation, but it is still in sync, so that currentConfig is still the previous value.
  3. The state is updated with the new value.

There are 2 ways to fix this:

  1. Use a useEffect: Listen to the currentConfig with a useEffect and trigger the animation, if the config changes.
React.useEffect(() => startConfigAnimation(currentConfig), [currentConfig])
  1. You are already passing the new/updated config to startConfigAnimation so you could be using that.

Upvotes: 1

Related Questions