How to sync props to state using React hooks : setState()

后端 未结 6 1161
深忆病人
深忆病人 2020-12-07 18:19

I am trying to set the state using React hook setState() using the props the component receive. I\'ve tried using the below code:

import React,{useState , us         


        
相关标签:
6条回答
  • 2020-12-07 18:46

    The props value in useState(props) is used only during the initial render, further state updates are done with the setter setNameState.

    In addition, there is no need for useEffect when updating derived state:

    const Person = props => {
      const [nameState, setNameState] = useState(props.name);
      // update derived state conditionally without useEffect
      if (props.name !== nameState) setNameState(props.name);
      // ... other render code
    };
    

    From React docs:

    [...] you can update the state right during rendering. React will re-run the component with updated state immediately after exiting the first render so it wouldn’t be expensive.

    [...] an update during rendering is exactly what getDerivedStateFromProps has always been like conceptually.

    In essence, we can optimize performance by getting rid of an additional browser repaint phase, as useEffect always runs after the render is committed to the screen.

    Working example

    This is a contrived example illustrating above pattern - in real code you would read props.name directly. See the React blog post for more appropriate derived state use cases.

    const Person = props => {
      const [nameState, setNameState] = React.useState(props.name);
      // Here, we update derived state without useEffect
      if (props.name !== nameState) setNameState(props.name);
    
      return (
        <p>
          <h3>Person</h3>
          <div>{nameState} (from derived state)</div>
          <div>{props.name} (from props)</div>
          <p>Note: Derived state is synchronized/contains same value as props.name</p>
        </p>
      );
    };
    
    const App = () => {
      const [personName, setPersonName] = React.useState("Lui");
      const changeName = () => setPersonName(personName === "Lukas" ? "Lui" : "Lukas");
    
      return (
        <div>
          <Person name={personName} />
          <button onClick={changeName}>Change props</button>
        </div>
      );
    };
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
    <div id="root"></div>

    0 讨论(0)
  • 2020-12-07 18:47

    useState hooks function argument is being used only once and not everytime the prop changes. You must make use of useEffect hooks to implement what you would call the componentWillReceiveProps/getDerivedStateFromProps functionality

    import React,{useState , useEffect} from 'react';
    
    const Persons = (props) =>  {
       const [nameState , setNameState] = useState(props)
    
       useEffect(() => {
           setNameState(props);
       }, [props])
    
       return (
                <div>
                    <p>My name is {props.name} and my age is {props.age}</p>
                    <p>My profession is {props.profession}</p>
                </div>
            )
    
    }
    
    export default Persons;
    
    0 讨论(0)
  • 2020-12-07 18:50

    This general idea can be put into hook:

    export function useStateFromProp(initialValue) {
      const [value, setValue] = useState(initialValue);
    
      useEffect(() => setValue(initialValue), [initialValue]);
    
      return [value, setValue];
    }
    
    
    function MyComponent({ value: initialValue }) {
      const [value, setValue] = useStateFromProp(initialValue);
    
      return (...);
    }
    
    0 讨论(0)
  • 2020-12-07 18:51
    import React, { useState, useEffect } from "react";
    
    const Persons = props => {
      // console.log(props.name);
    
      const [nameState, setNameState] = useState(props);
    
      console.log(nameState.name);
      console.log(props.name);
      useEffect(
        () => {
          if (nameState !== props) {
            setNameState(props);
          }
        },
        [nameState]
      );
      return (
        <div>
          <p>
            My name is {props.name} and my age is {props.age}
          </p>
          <p>My profession is {props.profession}</p>
        </div>
      );
    };
    
    export default Persons;
    

    As per the Hooks react document, all the time when any props is update or any update in component is there then useEffect will be called. So you need to check the condition before updating useState and then update your value so that it continuously doesn't do re-rendering

    0 讨论(0)
  • 2020-12-07 19:05

    For that, you need to use the useEffect so your code looks like. As you want to avoid to re-render again if pros didn't change then you have to check first on useEffect and then set the props to current variable.

    import React, { useState, useEffect } from "react";
    
    const Persons = props => {
      // console.log(props.name);
    
      const [nameState, setNameState] = useState(props);
    
      console.log(nameState.name);
      console.log(props.name);
      useEffect(
        () => {
          if (nameState !== props.name) {
            setNameState(props.name);
          }
        },
        [nameState]
      );
      return (
        <div>
          <p>
            My name is {props.name} and my age is {props.age}
          </p>
          <p>My profession is {props.profession}</p>
        </div>
      );
    };
    
    export default Persons;
    

    Demo

    0 讨论(0)
  • 2020-12-07 19:07

    I believe the problem indicates an attempt to use one conceptual variable or set of variables to do two different things. For example trying to get props.name and name to do the same thing.

    So if

    const [name, setName] = useState(props.name)
    

    isn't enough and you find yourself trying to force props.name into state variable name later in the function then maybe name is being overloaded. Try setting up another state variable - eg. updatedName and see if things work better.

    The original example doesn't demonstrate this problem since the state variables are never used except in log statements.

    If const [name, setName] = useState(props.name) updated on ever re-render there would be no point in having state variable name since it would always be the same as props.name (and further attempts to change it would cause re-render).

    0 讨论(0)
提交回复
热议问题