I have simple blog with articles. And I want to rewrite classes to functional components and hooks. Now I got this logic in lifecycle methods for my page with edit/add form: it works fine.
componentDidUpdate(prevProps, prevState) {
if (this.props.match.params.id !== prevProps.match.params.id) {
if (prevProps.match.params.id) {
this.props.onUnload();
}
this.id = this.props.match.params.id;
if (this.id) {
return this.props.onLoad(userService.articles.get(this.id));
}
this.props.onLoad(null);
}
this.isLoading = false;
}
componentDidMount() {
if (this.id) {
this.isLoading = true;
return this.props.onLoad(userService.articles.get(this.id));
}
this.isLoading = false;
this.props.onLoad(null);
}
componentWillUnmount() {
this.props.onUnload();
}
shouldComponentUpdate(newProps, newState) {
if (this.props.match.params.id !== newProps.match.params.id) {
this.isLoading = true;
}
return true;
}
I rewrote it all to hooks like that:
//componentDidMount
useEffect(() => {
if (id) {
setIsloading(true);
return props.onLoad(userService.articles.get(id));
}
setIsloading(false);
props.onLoad(null);
}, []);
useEffect(()=> {
prevId.current = id;
}, [id]
);
//componentDidUpdate
useEffect(() => {
//const id = props.match.params.id;
if (id !== prevId.current) {
if (prevId.current) {
props.onUnload();
}
if (id) {
return props.onLoad(userService.articles.get(id));
}
props.onLoad(null);
}
setIsloading(false);
});
//componentWillUnmount
useEffect(() => {
return props.onUnload();
}, []);
Its strange, but at localhost there is no error "Too many re-renders."
Don't know what to do with my class "shouldComponentUpdate" method how to rewrite it to hooks. Tryed 'memo' but have no idea how to write in in this case.
And anyway I'm missing something, because it all won't work - it's not updating form fields properly.
If you have a good knowledge with react hooks please help, or give some advice - how to fix it?
React Hooks provide a great deal of flexibility around implementing lifecycle methods. Unlike the class-based component approach, the Hooks lifecycle methods in a functional Hooks component allow the developer to decide how tightly or loosely coupled the lifecycle methods are.
The useEffect Hook allows us to replace repetitive component lifecycle code. Essentially, a Hook is a special function that allows you to “hook into” React features. Hooks are a great solution if you've previously written a functional component and realize that you need to add state to it.
Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don't work inside classes — they let you use React without classes. (We don't recommend rewriting your existing components overnight but you can start using Hooks in the new ones if you'd like.)
To get through this phase, four lifecycle methods are called: constructor , static getDerivedStateFromProps , render , and componentDidMount .
React lifecycle hooks All of the react component lifecycle stages help us handle most of the moments precisely and perform actions that we need at that moment, but not always we need them. In many applications, we will need to catch only moments when we init component, update, and unmount, without going for all of the small parts.
In react component lifecycle order, it’s called after getDerivedStateFromProps during the Mount cycle, or after shouldComponentUpdate and forceUpdate methods in Update cycle, new props or new components state will fire render method as well.
In many cases, we are forced to duplicate our logic in different lifecycle methods to implement an ‘effect logic’. Class components do not offer an elegant solution to sharing logic between components (HOC and friends are not an elegant solution) — React Hooks, on the other hand, give us the ability to build custom hooks, a much simpler solution.
For working with any tech you must know the lifecycle. When writing React components, we need access to lifecycle events to handle a variety of side effects: like fetching data on mount, changing props when the component updates, cleaning up before the component unmounts, etc. First, let’s take a look at how it’s been done traditionally.
The effect without dependency is causing "Too many re-renders."
: it runs after every render then it calls setIsLoading
to update the state( loading
) which will cause the component to re-render, which will run the effect
again and the setState
will be called again and effect
and so on...
//componentDidUpdate
useEffect(() => {
//const id = props.match.params.id;
if (id !== prevId.current) {
if (prevId.current) {
props.onUnload();
}
if (id) {
return props.onLoad(userService.articles.get(id));
}
props.onLoad(null);
}
setIsloading(false);
})
to fix the issue either remove the setIsLoading
from it, or add IsLoading
as dependency.
//componentDidUpdate
useEffect(() => {
...
setIsloading(false);
},[isLoading]);
you can also merge two mount effects into one like this ( yours is also working, but I think this is stylistically preferable):
//componentDidMount
useEffect(() => {
if (id) {
setIsloading(true);
return props.onLoad(userService.articles.get(id));
}
setIsloading(false);
props.onLoad(null);
//componentWillUnmount
return function () {
props.onUnload()
}
}, []);
for the second bullet: about rewriting your component's shouldComponentUpdate
; first I must point that your existing shouldComponentUpdate
isn't sound reasonable, since you always return true
, and you are only using it to trigger loading
state; and its not eligible to be written with React.memo (which is ~equivalent of shouldComponentUpdate
in class components); so you only need something to be executed on every props change to determine loading
state and for that you can use an effect with props
as its dependency like this:
//manually keeping old props id
const prevPropsId = useRef();
useEffect(() => {
if (prevPropsId.current !== props.match.params.id) {
setIsLoading(true);
}
prevPropsId.current = props.match.params.id;
}, [props.match.params.id]);
// this hook only run if `props.match.params.id` change
based on my realization this shall do the job, ( despite having hard time understanding why you write the logic this way in the first place) and if it's not doing fine you may tune the logic a little bit to match your needs, you get the idea how the props change effect works. also you many need to handle typeError
in case id
, params
or match
doesn't exist and
Optional chaining can be handy tool here -> props.match?.params?.id
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With