Loading... > @author: 郭瑞峰 > @createTime: 2023/07/10 > @updateTime: 2024/03/01 简介一下,前端`react hooks`是在`react@16.8`提出的新特性,为了简化 `class` 类组件,通过 `function` 函数式组件来实现原来 `class` 类组件。 # 先上结论 ## 常用的钩子函数 不废话,直接说一下常用的钩子函数 * `useState`: 用于在函数组件中添加状态 * `useEffect`: 用于在组件挂载、更新或卸载时执行副作用操作 * `useCallback`: 用于缓存函数实例,避免函数重复创建 * `useMemo`: 用于缓存计算结果,避免重复计算 * `useRef`: 用于在函数组件中创建 ref 对象 ## 不太常用的钩子函数 * `useContext`: 用于在组件中使用 React Context * `useReducer`: 用于在函数组件中使用 reducer 管理状态 * `useLayoutEffect`: 类似于 useEffect,但会在浏览器 layout 之后同步执行 # 详细说明 ### useState 数据读写 ```typescript import React, { useState } from 'react' export default function () { const [count, setCount] = useState<number>(0) return ( <div> <button onClick={() => setCount(val => val + 1)} >点了{ count }下</button> </div> ) } ``` ### useEffect * 在组件**挂载、更新或卸载**(生命周期)时执行操作,替代类组件中的生命周期方法 * 订阅外部数据源变化时更新状态或重新渲染组件(简单来说就是监控数据) * 异步执行 ```typescript import React, { useState, useEffect } from 'react' export default function () { const [count, setCount] = useState<number>(0) // 挂载、更新、卸载 useEffect(() => { console.log('组件装载') return () => { console.log('组件卸载了') } }) return ( <div> <p>count now is {count}</p> <button onClick={() => setCount(count + 1)}>+</button> </div> ) } ``` ### useCallback * 性能优化 * 防止父组件更新时无关紧要的子组件同步更新 ```typescript import React, { useState, useCallback } from 'react' function Child ({ onClick }) { return (<button onClick={onClick}>点我一下<button>) } function Parent () { const [count, setCount] = useState<number>(0) const addCount = useCallback(() => { setCount(val => val + 1) }, [count]) return (<> <div>你点击了{ count }次按钮</div> <Child onClick={addCount} /> </>) } ``` ### useMemo * 通过将计算结果缓存起来,可以提高组件的渲染性能 ```typescript import React, { useState, useEffect, useMemo } from 'react' function App () { const [second, setSecond] = useState<number>(10) useEffect(() => { let timer: any // 这里应该number和空,我偷懒了 ㄟ( ▔, ▔ )ㄏ if (second > 0) { clearTimeout(timer) timer = setTimeout(() => { setSecond(val => val - 1) }, 1000) } }, [second]) // 写一个有倒计时的按钮 const timerButton = useMemo(() => { return (<button>{ second }s</button>) }, second) return (<> <div> { /* 其他部分 */ } { timerButton } </div> </>) } export default App ``` ### useRef * 保存 DOM 元素的引用 ```typescript import React, { useRef } from 'react' function App () { const inputRef = useRef<HTMLInputElement>(null); const handleClick = () => { if (inputRef.current) { inputRef.current.focus() } }; return ( <div> <input type="text" ref={inputRef} /> <button onClick={handleClick}>Focus Input</button> </div> ); }; export default App ``` ### useContext(不太常用) * 函数组件中获取上下文对象中的值,不必通过 props 属性逐层传递 注:该功能一般通过三方库实现全局状态管理(如redux或recoil) ```typescript import React, { createContext, useContext } from 'react' interface Theme { backgroundColor: string textColor: string } const themes = { light: { backgroundColor: '#ffffff', textColor: '#000000' }, dark: { backgroundColor: '#000000', textColor: '#ffffff' } } const ThemeContext = createContext<Theme>(themes.light) const App = () => { return ( <ThemeContext.Provider value={themes.dark}> <Header /> <Main /> </ThemeContext.Provider> ) } const Header = () => { const theme = useContext(ThemeContext) return ( <header style={{ backgroundColor: theme.backgroundColor, color: theme.textColor }}> <h1>Header</h1> </header> ) } const Main = () => { const theme = useContext(ThemeContext) return ( <main style={{ backgroundColor: theme.backgroundColor, color: theme.textColor }}> <h2>Main</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> </main> ) } export default App ``` ### useReducer(不太常用) * 函数组件中管理状态 * 组件的状态和更新逻辑分离开来管理 注: * 若是多层关系,建议使用三方库实现全局状态管理(如redux或recoil) * 用于复杂的状态管理 ```typescript import React, { useReducer } from 'react'; type CounterState = { count: number } type CounterAction = { type: 'increment' | 'decrement', payload?: number } const initialState: CounterState = { count: 0 } const reducer = (state: CounterState, action: CounterAction): CounterState => { switch (action.type) { case 'increment': return { count: state.count + (action.payload || 1) } case 'decrement': return { count: state.count - (action.payload || 1) } default: throw new Error(`Unsupported action type: ${action.type}`) } } const Counter = () => { const [state, dispatch] = useReducer(reducer, initialState) const handleIncrement = () => { dispatch({ type: 'increment', payload: 5 }) }; const handleDecrement = () => { dispatch({ type: 'decrement' }) }; return ( <div> <p>Count: {state.count}</p> <button onClick={handleIncrement}>+5</button> <button onClick={handleDecrement}>-1</button> </div> ) } export default Counter ``` ### useLayoutEffect(有使用,但不频繁) * 与useEffect相似的 * 同步操作 * 可以用于获取dom尺寸等相关操作 缺点:同步执行,有可能会阻塞 UI 渲染 ```typescript import React, { useState, useLayoutEffect, useRef } from 'react' const Counter = () => { const [count, setCount] = useState<number>(0) const [rect, setRect] = useState<DOMRect | undefined>(undefined) const ref = useRef<HTMLDivElement>(null) useLayoutEffect(() => { if (ref.current) { setRect(ref.current.getBoundingClientRect()) } }, [count]) const handleIncrement = () => { setCount(count + 1) } return ( <div> <p>Count: {count}</p> <button onClick={handleIncrement}>+1</button> <div ref={ref}> {rect && ( <> <p>Width: {rect.width}</p> <p>Height: {rect.height}</p> </> )} </div> </div> ) } export default Counter ```  最后修改:2024 年 11 月 27 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏