React lifecycle and Rendering

Codylillyw
3 min readFeb 23, 2023

Without useEffect

Use Case: When some information needs to be updated on every render or comes from a hook other than useEffect since hooks must be within react components rather than nested in each other. The page will render every time a value changes causing these values to be updated. You cant use this like state because it does not know when the data has changed without useState.

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

Class component constructor, render, and shouldComponentUpdate methods

Functions passed to useState, useMemo, or useReducer

This means the initial useEffect calls will occur twice if you are using Strict mode.

const Component = () => {
const number = 5;
console.log("rerendered");
return (<div>{number}</div>);
}

Mount

Use Case: If you need something to only happen once after the first render when it is mounted. The only way this will be triggered again is if the page reloads. Changing query params on the same page will not trigger it it mount becuase it still exists on the page.

If a component came to exist such as appearing on a page it has mounted.

Example:

useEffect(() => {
//code to happen on first render
}, [])

Update

When we update a dependency the callback is put on the stack of things to be updated.

Use Case: When you want to control when a set of code runs based on changes to state.

Example:

useEffect(() => {
//Runs every time the state changes
}, [state])

Unmount

A component unmounts when it no longer appears on the screen.

Use Case: If we are using useEffect to fetch from an API then we should use this return statement to cleanup in the case that the component unexpectedly unmounts before the request is completed.

The error will look something like this:

Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

We can use a flag or a AbortController. If we do not need to support IE AbortController is a better option because the preflight request would remain in the background consuming user bandwidth and taking up one of the browser’s max concurrent requests.

Example:

useEffect(() => {
return () => {
//Runs when component unmounts.
}
}, [])
useEffect(() => {
let abortController = new AbortController();
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1', {
signal: abortController.signal,
});
const newData = await response.json();
setTodo(newData);
}
catch(error) {
if (error.name === 'AbortError') {
// Handling error thrown by aborting request
}
}
};
fetchData();
return () => {
abortController.abort();
}
}, []);

React Lifecycle Methods in Functional Components | by Yogesh Datir | JavaScript in Plain English | JavaScript in Plain English

Components in components

In Formik you are required to place useEffect in its own component in order to access formiks data. In a case like this make sure the component is not defined inside the initial component to avoid infinite rerenders as every time the parent component renders the child will also rerender which means a lot more mounting than you likely intended.

Why isnt this rerendering

If you are attempting to change state one of two things is happening:

  • You are not setting state with useState

You must use the setter from useState. Trying to set this manually will cause unexpected issues.

  • The reference is not changing

To fix this if you are using an array you can destructuring to change the reference. ie. […myState]

Using many useEffects

If there is a direct relationship between data we should avoid using more than one useEffect.

rerenders with context/redux

Passing down the store state will cause all the descendant nodes to re-render.

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.

This is why one global state is not recommended and context API is better suited for state which is not changing frequently (theme, localization, auth…). If you use context API you should split the context.

References

How useEffect works in ReactJS ? — GeeksforGeeks

useEffect under the Hood (bussieck.com)

When does React re-render components? | Felix Gerschau

Avoiding race conditions and memory leaks in React useEffect — Wisdom Geek

React Lifecycle Methods in Functional Components | by Yogesh Datir | JavaScript in Plain English | JavaScript in Plain English

--

--

Codylillyw

I am a Software engineering student in my senior year with most of my experience in web development and related technology.