Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React lifecycle methods to hooks

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();
  }, []);

  1. I got error - "Too many re-renders." at codesandbox full code: codesandbox

Its strange, but at localhost there is no error "Too many re-renders."

  1. 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.

  2. 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?

like image 591
Will Black Avatar asked Dec 16 '20 14:12

Will Black


People also ask

Does React Hooks have lifecycle methods?

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.

Do Hooks replace lifecycle methods?

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.

What are React lifecycle Hooks?

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.)

How many lifecycle Hooks are in React?

To get through this phase, four lifecycle methods are called: constructor , static getDerivedStateFromProps , render , and componentDidMount .

What is the use of react lifecycle hooks?

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.

What is React component lifecycle order?

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.

Why react hooks are better than class components?

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.

Why do we need lifecycle events in react?

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.


1 Answers

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

like image 105
Mhmdrz_A Avatar answered Oct 07 '22 09:10

Mhmdrz_A