简体   繁体   中英

React Node in state keep remember props

I have trouble debugging this code.

I have an App component:

function App() {
  const [state, setState] = useState(0);

  const onSelectItem = () => {
    console.log("🐞: onSelectItem -> currentState", state);
  };

  // items is an array of ReactNode: button, when click on it. It will log the currentState.
  const items = ["FirstItem", "SecondItem"].map(item =>  (
      <button key={item} onClick={() => onSelectItem()}>
        {item}
      </button>
    );
  );

  return (
    <div className="App">
      <Menu items={items} />
      <hr />
      <button onClick={() => setState(prevState => prevState + 1)}>Change State</button>
    </div>
  );
}

My Menu components will receive items prop, and render it. It also has ability to set the active item. For simplicity's sake, I render a button to set activeItem to the first one. The active item will also be rendered.

  function Menu({ items }) {
      const [activeItem, setActiveItem] = useState(items[0]);
      return (
        <div>
          {items}
          <hr />
          {activeItem}
        </div>
      );
    }

Now, come to the main part:

  • I press the button (before hr ) => it shows currentState (OK)
  • I press the active button (after hr ) => it shows currentState (OK)
  • I press change state button => the state now changes to 1 (OK)
  • Now, if I press the button (before hr ) => It shows currentState is 1 (OK)
  • But, if I press the active button (after hr ) => It still shows 0 (which is the last state) (???)

My guess is React keeps remembering everything when using useState . But I'm not sure. Could anyone explain this for me!

I also include the snippets for you to easily understand my problem.

 const {useState} = React; function Menu({ items }) { const [activeItem, setActiveItem] = useState(items[0]); return ( <div> {items} <hr /> <span>Active Item:</span> {activeItem} </div> ); } function App() { const [state, setState] = useState(0); console.log(state); const onSelectItem = () => { console.log("🐞: onSelectItem -> currentState", state); }; const items = ["FirstItem", "SecondItem"].map(item => { return ( <button key={item} onClick={() => onSelectItem()}> {item} </button> ); }); return ( <div className="App"> <Menu items={items} /> <hr /> <button onClick={() => setState(prevState => prevState + 1)}>Change State</button> </div> ); } ReactDOM.render(<App />, document.getElementById('app'));
 <div id="app"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="react"></div>

You are trying to access the state from App component in your Menu component.

State is local to that component and can't be accessed outside, if you would like to access the state outside the component you can refer to the useContext hook implementation.

https://reactjs.org/docs/hooks-reference.html#usecontext

Reason you are seeing 0 in the Active state is that is the default value of useState.

You need to pass key to your menu component.

Whenever there is change in props, the component has to re-render with new props.

Refer this artcile from their official docs - https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

Change I made is passing state as key to Menu component

 const {useState} = React; function Menu({ items }) { const [activeItem, setActiveItem] = useState(items[0]); return ( <div> {items} <hr /> <span>Active Item:</span> {activeItem} </div> ); } function App() { const [state, setState] = useState(0); console.log(state); const onSelectItem = () => { console.log("🐞: onSelectItem -> currentState", state); }; const items = ["FirstItem", "SecondItem"].map(item => { return ( <button key={item} onClick={() => onSelectItem()}> {item} </button> ); }); return ( <div className="App"> <Menu items={items} key={state}/> <hr /> <button onClick={() => setState(prevState => prevState + 1)}>Change State</button> </div> ); } ReactDOM.render(<App />, document.getElementById('app'));
 <div id="app"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="react"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM