Learning the React Framework - 006 Advanced Hooks and Render Control
With just useState and useEffect, you can actually build simple applications. However, development requirements are often more complex and conditional - we can't just render components immediately whenever dependencies change. We need temporal, operational, and holistic planning. React has also introduced more advanced control functions to allow developers to create richer and more refined operations.
Advanced Hooks
useReducer
Compared to useState, it's easier to operate complex object structures and can update state based on conditions.
- reducer: The reducer function that specifies how state should be updated. It must be pure, should take state and action as parameters, and should return the next state. State and action can be of any type.
- initialArg: The value used to calculate the initial state. It can be a value of any type. How the initial state is calculated from it depends on the next init parameter.
- optional init: The initialization function that should return the initial state. If not specified, the initial state is set to initialArg. Otherwise, the initial state will be set to the result of calling init(initialArg). This can avoid recreating the initial state, i.e., lazy initialization.
- state: The current state
- dispatch: Function that can update state to a different value and trigger re-rendering.
In strict mode, React will call the reducer and initializer twice to help you find accidental impurities. This is development-only behavior and does not affect production.
By separating it into actionType and reducer encapsulation, we can perform more complex object operations, and through IDE hints, we can quickly find corresponding operation methods. Note that the official documentation repeatedly mentions the need to provide pure operations to avoid side effects causing unexpected component changes and rendering.
useCallback
Optimizes function callbacks, but whether it's necessary in usage still requires self-judgment, as it might not optimize and even become slower QQ
The first parameter is the cached function value, and the second parameter is a dependency array, similar to useEffect
.
When a dependency changes between renders, the callback passed in the first parameter will be the callback returned from useCallback
. If they haven't changed, you'll get the previously returned callback (so the callback remains the same between renders).
Through useCallback, you can remember the memory location of a function, which can avoid React.memo re-rendering when comparing props values due to different memory locations but same values for object types.
However, since this Hook uses a caching pattern, unless specifically necessary, it will increase memory burden.
useContext
This Hook is very interesting. Through function encapsulation of your own context environment, more simply put, React provides a global state passing method. When application-level complexity and nesting occur, it can effectively pass state.
- SomeContext: Context created using createContext. The context itself doesn't hold information, it just represents the type of information you can provide or read from components
- value: useContext returns the context value for the calling component. It's determined as the value passed to the nearest SomeContext.Provider above the calling component in the tree.
React will automatically re-render all children using a particular context, starting from the provider that receives a different value. Previous and next values are compared with Object.is. Skipping re-renders with memo doesn't prevent children from receiving fresh context values.
useLayoutEffect
useLayoutEffect is a version of useEffect that fires before the browser repaints the screen. When development requirements need to get certain data or state at the beginning, this can be used.
- before any other effects are called.
- if the side effect that you are performing makes an observable change to the dom, that will require the browser to paint the update that you made.
Only runs on the client. They don't run during server rendering. Code in useLayoutEffect and all state updates scheduled from it block the browser from repainting the screen. When overused, this makes your app slow QQ
useMemo
Can cache calculation results between re-renders.
- calculateValue: Function to calculate the value to cache. Should be pure, should have no arguments, and should return a value (of any type). React will call this function during initial render. On next renders, if dependencies haven't changed since the last render, React will return the same value again. Otherwise, it will call calculateValue, return its result, and store it so it can be reused later.
- dependencies: List of all reactive values referenced inside calculateValue code. Reactive values include props, state, and all variables and functions declared directly inside your component body.
Only rely on useMemo as a performance optimization. Don't use it extensively.
Although it's similar to useCallback, there are still some contextual differences in usage.