Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 , useEffect} from 'react';  const Persons = (props) =>  {      // console.log(props.name);     const [nameState , setNameState] = useState(props)     console.log(nameState.name);    console.log(props.name);     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; 

The issue is the state is being set upon component being loaded. But when it receive new props, the state is not getting updated. How to update the state in this case? Thanks in advance.

like image 508
METALHEAD Avatar asked Feb 11 '19 07:02

METALHEAD


People also ask

How do you pass Props to state in React hooks?

Passing props to state using useState Hooks import React, { useState } from 'react'; const Profile = props => { const [profileState, setProfileState] = useState(props); return ( <div> <p> <strong>Name:</strong> {profileState.name} </p> <p> <strong>Email:</strong> {profileState.

Why do you need to use setState () to update state in React?

The setState() Method State can be updated in response to event handlers, server responses, or prop changes. This is done using the setState() method. The setState() method enqueues all of the updates made to the component state and instructs React to re-render the component and its children with the updated state.

Can we use props in useState?

Since the DetailView then doesn't need any local state at all, we won't have the problem of putting props into state. Now, the App has full control over all the state, and the DetailView is just a so-called "dumb component". This approach is feasible for many use-cases, but it's not without drawbacks.


2 Answers

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; 
like image 63
Shubham Khatri Avatar answered Sep 21 '22 14:09

Shubham Khatri


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>
like image 33
ford04 Avatar answered Sep 18 '22 14:09

ford04