React Hooks are a new feature introduced in React 16.8 that allow the use of state and other React features in functional components. Here are some of the main ones
React Hooks:
useState
: is a React Hook that allows adding and managing state in functional components. Before this, only class components could have their own state.useState
Returns an array containing the current state value and a function that updates the state.
Basic usage is as follows:
import React, { useState } from 'react';
function Example() {
// 声明一个新的状态变量,其初始值为 0
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
In this example:
-
const [count, setCount] = useState(0);
creates a new state variablecount
and a function that updates this statesetCount
. -
When the user clicks the button, call
setCount(count + 1)
to update the status. -
State changes will trigger the component to re-render, and the new state value will be reflected on the interface.
Note that the
setCount
function does not modify the state immediately, but creates a new state object and schedules the component for re-rendering. This is because in React, all state updates are asynchronous.You can also pass a function to
setCount
to calculate the next state value, which ensures that the latest state is always used:<button onClick={() => setCount((prevCount) => prevCount + 1)}> Click me </button>
Additionally, if the state is a complex data structure (such as an object or array) and you need to create a new state based on an existing state, you should use a functional updater to avoid state mutation problems.
useEffect
: is a React Hook that allows side-effect operations to be performed in functional components. These side effects may include data fetching, subscribing, manually changing the DOM output of the React component, etc.useEffect
can be viewed as a combination of thecomponentDidMount
,componentDidUpdate
, andcomponentWillUnmount
lifecycle methods.
Basic usage is as follows:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 使用 Effect Hook 来监听 count 状态的变化
useEffect(() => {
document.title = `You clicked ${count} times`;
return () => {
// 清理工作(可选)
};
}, [count]); // 当依赖项数组中的值改变时,重新运行 effect
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
In this example:
-
useEffect
Receives two parameters: a function containing the side-effect code to be executed and an array of dependencies. -
When the component is rendered and mounted on the DOM, the side effect function in
useEffect
will be called once. This is similar to thecomponentDidMount
lifecycle methods. -
When the value in the dependency array changes, the side-effect function in
useEffect
will be called again. This is similar to thecomponentDidUpdate
lifecycle methods. -
If a cleanup function is specified to be returned, then when the component is uninstalled or a dependency change causes the effect to be recalculated, this cleanup function will be executed before the next effect is run. This is similar to the
componentWillUnmount
lifecycle methods.Note that if the second parameter (the dependencies array) is omitted, the effect will only run when the component is mounted and unmounted, not after each render. This can be used to simulate the
componentDidMount
andcomponentWillUnmount
lifecycle methods.
useContext
: is a React Hook that allows access to context objects in functional components. The React context API allows data to be passed around the component tree without having to manually go through each level ofprops
.
Basic usage is as follows:
import React, { createContext, useContext } from 'react';
// 创建一个新的 context 对象
const ThemeContext = createContext();
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
// 使用 useContext 获取当前的 theme 值
const theme = useContext(ThemeContext);
return <button style={
{ background: theme }}>Click me</button>;
}
In this example:
-
First creates a new context object
ThemeContext
. -
Then use in the
App
component to provide the context value.<ThemeContext.Provider>
-
In the child component
ThemedButton
, we useuseContext(ThemeContext)
to get the current context value (i.e. theme).useContext
What is returned is the value of the current context. When the value of context changes, all components subscribed to this context will be re-rendered.Note that if you use without wrapping
<Provider>
, the default value of context will be returned. Additionally, to avoid unnecessary re-rendering, you should place calls to as close as possible to the component that needs to use these values.useContext
useContext
useReducer
: is a Hook in React that allows managing complex, reusable logic in functional components.useReducer
Receives a reducer function and initial state as parameters, and returns the current state and the dispatch method for updating the state.
Basic usage is as follows:
import React, { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, 0);
return (
<>
Count: {state}
<button onClick={() => dispatch({ type: 'increment' })}>
+
</button>
<button onClick={() => dispatch({ type: 'decrement' })}>
-
</button>
</>
);
}
In this example:
-
We first define a
reducer
function, which receives two parameters: the current state and an action object. Depending on the action type, we can decide how to update the state. -
In the
Counter
component, we useuseReducer
to create a new state variable (initialized to 0) and a dispatch method. The dispatch method is used to send an action to the reducer to update the state. -
When the user clicks the button, we send the corresponding increase or decrease action object to the reducer through the dispatch method, and then the state will be updated accordingly.
useReducer
can replace multipleuseState
calls, especially if your component needs to maintain multiple related state values. Additionally, since reducers are pure functions, this makes testing easier.
-
useCallback
:` is a Hook in React, which is used to optimize performance. When you use inline callbacks (such as event handlers) in a function component, a new function instance is created with each render. This may cause unnecessary re-rendering of child components, even if they don't rely on these callbacks.useCallback
Receives two parameters: a callback function that requires memoize and an array of dependencies. The returned memoized callback function is updated when the values in the dependencies array change; otherwise, it returns the previously cached version.
Basic usage is as follows:
import React, { useCallback } from 'react';
function Example({ a, b }) {
// 使用 useCallback 来记住计算的值
const memoizedCallback = useCallback(
() => {
console.log(a + b);
},
[a, b] // 当 a 或 b 变化时,重新计算
);
return (
<button onClick={memoizedCallback}>
Click me
</button>
);
}
In this example:
-
We define a callback function containing the addition operation of
a
andb
, and return a throughuseCallback
memoized version. -
If the value of
a
orb
changes,useCallback
will return a new memoized callback function; otherwise, It will return the previously cached version. -
When the user clicks the button, we trigger the memoized callback function. This avoids unnecessary re-rendering of child components because the callback function will not change unless the value of
a
orb
changes.Note that only when your callback function is passed to the subcomponent and the subcomponent executes
shouldComponentUpdate()
or usesReact.memo()
, will not bring any benefit.useCallback
can really improve performance. If your callback function is only used for internal operations (such as directly manipulating the DOM), then usinguseCallback
-
useMemo
: is a Hook of React, which is used to optimize performance. When you perform expensive calculations or create complex objects in functional components, these operations are re-done every time you render. This may cause unnecessary performance overhead.useMemo
Receives two arguments: a value to memoize (usually the return result) and an array of dependencies. The returned memoized value is updated when the values in the dependencies array change; otherwise, it returns the previously cached version.Basic usage is as follows:
import React, { useMemo } from 'react';
function Example({ a, b }) {
// 使用 useMemo 来记住计算的值
const memoizedValue = useMemo(() => {
console.log('Computing expensive value...');
return a + b;
}, [a, b]); // 当 a 或 b 变化时,重新计算
return <div>{memoizedValue}</div>;
}
In this example:
-
We define an addition operation involving
a
andb
, and return a memoized version viauseMemo
. -
If the value of
a
orb
changes,useMemo
will return a new memoized value; otherwise, it Will return the previously cached version. -
Each time we render, we use the memoized value instead of the recalculated result.
Note that only when your calculation result is passed to the subcomponent and the subcomponent executes
shouldComponentUpdate()
or usesReact.memo()
, will not bring any benefit.useMemo
can really improve performance. If your calculation results are only used for internal operations (such as directly manipulating the DOM), then usinguseMemo
useRef
: is a React Hook that allows the creation of mutable references in function components. This Hook returns aref
object whose.current
properties are initialized to the passed argument (initialValue
). The returned object remains unchanged throughout the component's lifetime.
Basic usage is as follows:
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
// 创建一个 ref 来保存文本输入框的 DOM 元素
const inputEl = useRef(null);
const onButtonClick = () => {
// 当按钮被点击时,使文本输入框获取焦点
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
In this example:
-
We create a new ref by calling
useRef()
and assign it to theinputEl
variable. -
On the
<input>
tag, we assigninputEl
to theref
attribute. In this way, React will bind the corresponding DOM element toinputEl.current
. -
When the user clicks the button, we can make the text input box gain focus by calling
inputEl.current.focus()
.Note that
useRef()
can be used not only on DOM elements, but also on any type of variable. Its main use is when a value or object needs to be preserved between different renderings.
useImperativeHandle
: is a Hook in React, which is used to customize theref
value exposed to the parent component. Normally, we can access some instance methods or properties inside the subcomponent throughref
. However, in some scenarios, we may want to expose some specific methods or properties instead of the entire instance by default.
Basic usage is as follows:
import React, { forwardRef, useImperativeHandle } from 'react';
function FancyInput(props, ref) {
const inputEl = useRef(null);
// 使用 useImperativeHandle 来暴露 customMethod 给父组件
useImperativeHandle(ref, () => ({
focus: () => {
inputEl.current.focus();
},
customMethod: () => {
console.log('I am a custom method');
}
}));
return <input ref={inputEl} type="text" />;
}
// 使用 forwardRef 将 ref 转发到 FancyInput 中
const WrappedFancyInput = forwardRef(FancyInput);
function ParentComponent() {
const fancyInputRef = useRef(null);
const handleClick = () => {
// 在父组件中调用子组件的 customMethod 方法
fancyInputRef.current.customMethod();
};
return (
<>
<WrappedFancyInput ref={fancyInputRef} />
<button onClick={handleClick}>Call Custom Method</button>
</>
);
}
In this example:
-
We create a function component named
FancyInput
and use theforwardRef
higher-order function to receive aref
Parameters. -
Inside
FancyInput
we useuseImperativeHandle
to define the methods and properties to be exposed to the parent component. Here we expose thefocus
andcustomMethod
methods. -
The parent component passes the object to the child component through the
ref
attribute. In this way, the parent component can access the and methods exposed by the child component through .ref
WrappedFancyInput
fancyInputRef.current
focus
customMethod
Note that overusing
useImperativeHandle
may result in code that is difficult to understand and maintain. Therefore, you should try to avoid directly manipulating the DOM of child components and instead use React's data flow for communication whenever possible.
-
useLayoutEffect
: is a React Hook, it is similar touseEffect
, but has two key differences:useLayoutEffect
Called synchronously after all DOM changes, but before the browser draws. This allows you to read the layout and trigger a re-render synchronously.- In server-side rendering,
useLayoutEffect
will not be executed.
Basic usage is as follows:
import React, { useLayoutEffect } from 'react';
function Example() {
useLayoutEffect(() => {
// 这里可以访问到最新的 DOM 样式和几何信息
console.log('DOM 已经更新,但我还没有被绘制');
});
return <div>Example</div>;
}
In this example:
-
When the component completes rendering, the callback function within
useLayoutEffect
will be executed. At this point, all DOM updates have been completed, but the browser hasn't started drawing yet. -
If you need to access or modify the DOM (such as setting styles) before the browser draws, you should use
useLayoutEffect
.Note that overuse
useLayoutEffect
may cause visual flickering or performance issues. Therefore, you should try to avoid blocking the browser's rendering process and use standarduseEffect
to handle side effects whenever possible.
useDebugValue
: is a React Hook, which is used to display custom hook labels in the React developer tools. This is useful for debugging complex custom hooks.
Basic usage is as follows:
import React, { useDebugValue } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// 获取 friendID 对应的好友在线状态
// ...
// 使用 useDebugValue 来为这个 hook 显示一个可读的标签
useDebugValue(isOnline ? '在线' : '离线');
return isOnline;
}
function FriendStatus() {
const isOnline = useFriendStatus(123456);
return (
<span>{isOnline ? '在线' : '离线'}</span>
);
}
In this example:
-
We created a custom hook named
useFriendStatus
that receives afriendID
parameter and returns the friend's online status. -
Inside
useFriendStatus
, we useuseDebugValue
to display a human-readable label for this hook. This tag will be displayed in the component tree of the React developer tools. -
In the
FriendStatus
component, we calleduseFriendStatus
and rendered the corresponding online state.Note that
useDebugValue
only works in development mode and will only affect display in the React Developer Tools. Therefore, in a production environment, you don't need to worry about the additional performance overhead it brings.
These are the core React Hooks. In addition, the community has developed many other custom Hooks, such as useDebounce
, useThrottle
, etc., to solve specific problems. Questions and Scenarios.