You should check the docs
You can have a state for the previous path and the current path and only call setLoginStatus when they are different.
If you only want to setLoginStatus(true) when path == 'login' then using the useEffect is correct.
This part of the code will only run when path changes. And this happens because of [ path ].
useEffect(() => {
if (path ==='/login'){
setLoginStatus(true)
} else {
setLoginStatus(false)
}
}, [ path ])
And if you are using some router, probably your effect will run only in the initial render.
I'm just wondering if I'm not losing anything by converting to this.
No, it's fine, that's the way you should do it
Also take a look at You Probably Don't Need Derived State
And here
Answer from Vencovsky on Stack Overflowreactjs - How to sync props to state using React hooks : setState() - Stack Overflow
Newest 'getderivedstatefromprops' Questions - Stack Overflow
Hooks refactoring of getDerivedStateFromProps/componentDidUpdate and shouldComponentUpdate to prevent re-rendering
How to use lifecycle method getDerivedStateFromProps as opposed to componentWillReceiveProps
Videos
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;
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
getDerivedStateFromPropshas 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>
About the removal of componentWillReceiveProps: you should be able to handle its uses with a combination of getDerivedStateFromProps and componentDidUpdate, see the React blog post for example migrations. And yes, the object returned by getDerivedStateFromProps updates the state similarly to an object passed to setState.
In case you really need the old value of a prop, you can always cache it in your state with something like this:
state = {
cachedSomeProp: null
// ... rest of initial state
};
static getDerivedStateFromProps(nextProps, prevState) {
// do things with nextProps.someProp and prevState.cachedSomeProp
return {
cachedSomeProp: nextProps.someProp,
// ... other derived state properties
};
}
Anything that doesn't affect the state can be put in componentDidUpdate, and there's even a getSnapshotBeforeUpdate for very low-level stuff.
UPDATE: To get a feel for the new (and old) lifecycle methods, the react-lifecycle-visualizer package may be helpful.
As we recently posted on the React blog, in the vast majority of cases you don't need getDerivedStateFromProps at all.
If you just want to compute some derived data, either:
- Do it right inside
render - Or, if re-calculating it is expensive, use a memoization helper like
memoize-one.
Here's the simplest "after" example:
import memoize from "memoize-one";
class ExampleComponent extends React.Component {
getDerivedData = memoize(computeDerivedState);
render() {
const derivedData = this.getDerivedData(this.props.someValue);
// ...
}
}
Check out this section of the blog post to learn more.