How useState and useEffect work internally in React
Understanding how useState
and useEffect
work internally in React provides insights into their behavior and optimizations within functional components.
useState Internals
-
Initialization:
- When a functional component is rendered for the first time, React initializes the state using the initial value provided to
useState
. - It stores the current state value (
value
) and a function (setValue
) to update that state.
- When a functional component is rendered for the first time, React initializes the state using the initial value provided to
-
State Management:
- React uses closures to maintain the current state between re-renders without losing its value.
- Each call to
useState
returns the current state value and a function to update it (setValue
).
-
Updating State:
- When
setValue(newValue)
is called, React schedules a re-render of the component with the updated state value. - It uses a queue mechanism to batch state updates for performance optimization.
- When
-
Re-rendering:
- React compares the new state value (
newValue
) with the previous one (value
) using a shallow comparison (Object.is
). - If they differ, React schedules a re-render to reflect the updated state in the UI.
- React compares the new state value (
useEffect Internals
-
Effect Registration:
- When a component renders, React processes the
useEffect
hook declarations. - It registers the effect function (
effect
) to be called after the component renders and the DOM is updated.
- When a component renders, React processes the
-
Dependency Management:
- If the
useEffect
hook has a dependency array ([]
), React checks the dependencies after every render. - If any dependency has changed since the last render, React schedules the effect function (
effect
) to run after the component updates.
- If the
-
Cleanup:
- If the effect function (
effect
) returns a cleanup function, React saves it. - Before running the effect next time or before unmounting the component, React calls the cleanup function to clean up any resources used by the previous effect.
- If the effect function (
-
Optimization:
- React optimizes
useEffect
by running effects asynchronously after rendering, batching updates, and ensuring consistent timing. - It ensures that effects do not block the main thread, promoting smooth UI updates.
- React optimizes
Example of Internal Behavior
Consider a simple example demonstrating useState
and useEffect
:
import React, { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
// Effect function
console.log('Effect: Component has rendered or updated');
document.title = `Clicked ${count} times`; // Example of side effect
}, [count]); // Dependency array: run effect only when `count` changes
const increment = () => {
setCount(count + 1);
};
return (
<div>
<h2>Counter</h2>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
Explanation:
- useState: Initializes
count
state to0
.setCount
updatescount
. - useEffect: Registers a side effect to update the document title whenever
count
changes. - Component Behavior: React manages state updates (
useState
) and schedules effects (useEffect
) after rendering, ensuring efficient state management and UI updates.
Published on: Jul 05, 2024, 06:29 AM