For every state change, the page will be re-rendered again, the state , variable , function, useEffect in the render scope will be independent to previous one
For each rendering, the functional component will be returned and then triggered useEffect
The virtual dom will be saved in memory and will be compared with the previous virtual dom with its internal differing algorithm, and just update the changed part on the real dom which is into dom which id is root so as to increase the efficiency
Hook
useState
When you call setState, React schedules the state update and marks the component for a re-render. This scheduling is asynchronous
React batched state updates in event handlers to reduce the number of re-rendering
// number is a state, setNumber is a setter method
const [number, setNumber] = useState(1);
// put the value into setter to set the value directly
setNumber(2);
// put the update function into setter
// to set the value which is based on previous value
setNumber(prevNum => prev + 1);
// Not recommended
setNumber(number + 1);
function init () {
console.log('run function');
return 4;
}
// Run Everytime when changing the state
const [count, setCount] = useState(4);
const [count, setCount] = useState(init());
// Run only the very first time when your component render
const [count, setCount] = useState(() => init());
useEffect
It is used to listen the dependencies change, e.g: state, and execute the side effect, which is equal to lifecycle event of class component
When the component is mounted, the side effect will be triggered once first.
When component is unmounted, the return function will be triggered and based on the previous useEffect. After the new user interface finish re-rendering, , and finally trigger the new useEffect function
As the function in render scope is put in useEffect, it is recommended to put the function in the dependency array
As we do not want the useEffect always be triggered as the function is always be changed in every re-rendering, so we use useCallback to save the function except the dependency is changed
As async function have the delay, we cannot make sure of order of the setState. In order to prevent from set the wrong data which is based on the the value or state in previous rendering, it is recommended to make return function to stop setting wrong value after the state is updated
function Article({ id }) {
const [article, setArticle] = useState(null);
useEffect(() => {
let didCancel = false;
async function fetchData() {
const article = await API.fetchArticle(id);
if (!didCancel) {
setArticle(article);
}
}
fetchData();
return () => {
didCancel = true;
};
}, [id]);
// ...
}
UseContext
Share all the data from component with upper layer to components with lower layer without passing props
It is an advanced version of useState, since the setting function of the useState is only allow one situation and one return value. But useReducer can return different base on the the type, it is more suitable to handle more complicated logic
useContext/useReducer : it is easier to setup and more suitable to put variables with low-frequency update on it , since every time the variable passed by useContext, the area inside the provider will be re-rendered
Redux: it is more complicated to setup, and middleware is allowed to use to handle async function. each component will subscribe (add listener) to their connected state. If the correspondent state is changed, the listener will be triggered, so that only that component will be re-rendered but not whole of the area inside the provider
useCallback
When the component is re-rendered, the functions will also be re-rendered. The purpose of useCallback is return the memorized callback function until the one of the dependency is changed.
const [delta, setDelta] = useState(1);
const [c, setC] = useState(0);
// the function will keep the same, which means delta always be 1,
// and listen to the dependency c , if c is changed ,
// the function will be re-rendered and updated
const incrementDeltaWithCallBack = useCallback(() => {
setDelta(delta + 1);
console.log("increaseDelta");
}, [c]);
const incrementWithCallBack = useCallback(() => {
setC(c + 1);
console.log("increment");
}, [delta]);
useMemo
When the component is re - rendered, the variable will also be re-rendered. The purpose of useMemo is return the memorized value until the one of the dependency is changed.
const [delta, setDelta] = useState(1);
// even setDelta is triggered, but value of testMemo will
// be the same, always be 1, will not be re-rendered
const testMemo = useMemo(() => delta, []);
useMemo vs useCallback
The effect of useMemo can equal to useCallback in this case
The time of the first time re-rendering will be much larger as it memorizes the value/function
The ram consumed in the browser will be much larger
The condition of using useMemo/ useCallback
The variable require long time to be rendered , for example : have a larger loop and return the result
The function is called in useEffect
useRef
The current property will be initialized by passing the argument , and if the current is changed, it will be saved, but the component will not be re-rendered, it can be used to store the value which is not related to the ui
const testRef = useRef(0);
const test = () => {
console.log(testRef.current); // 0
testRef.current++;
return (<div>{testRef.current}</div>)
// next time testRef.current will be 1 ...
// but the ui still show 0
}
The reference object can be acted as the ref of the element, so that the current property will be corresponded to the html element. We can make use good use of the reference to manipulate the element, such as focus
function Tooltip() {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(0); // You don't know real height yet
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height); // Re-render now that you know the real height
}, []);
// The component only render once when using layout effect
// useLayoutEffect: render with height
// useEffect: render with 0 -> render with height
}
useTransition
The function you pass to startTransition must be synchronous. React immediately executes this function, marking all state updates that happen while it executes as Transitions.
The hook can be used prioritize the state update . A state update marked as a Transition will be interrupted by other state updates and marked as lower priority
If there are multiple ongoing Transitions, React currently batches them together.
The state update inside the startTransition will be non-blocking, which means that the state update will not be blocked by heavy computation and be freeze, it will interrupt the slow rendering immediately
import { useTransition } from 'react';
const [isPending, startTransition] = useTransition();
// Urgent: Show what was typed
setInputValue(input);
// Mark any non-urgent state updates inside as transitions
startTransition(() => {
// Transition: Show the results
setSearchQuery(input);
});
useDeferredValue
The deferred value is considered as a low priority, its deferred “background” rendering is interruptible even if the deferred value is updated.
For example, if you type into the input again, React will abandon it and restart with the new value. Also, network request is pending, the rendering is also be suspended
useDeferredValue lets you prioritize updating the input (which must be fast) over updating the result list (which is allowed to be slower)
useOptimistic (React 19)
It provides a function that takes the current state and the input to the action, and returns the optimistic state to be used while the action is pending.
The state is called the “optimistic” state because it is usually used to immediately present the user with the result of performing an action, even though the action actually takes time to complete.
It pass useActionState an existing form action function as well as an initial state, and it returns a new action that you use in your form, along with the latest form state and pending state
Can do a custom hook and apply to different component instead of making high order component
useLayoutEffect is a version of that fires before the browser repaints the screen, to enhance the user experience and the shift of component
The code inside useLayoutEffect and all state updates scheduled from it block the browser from repainting the screen. When used excessively, this makes your app slow. When possible, prefer