admin管理员组文章数量:1585012
一、回顾一下Hooks的概念
Hooks 是 React 16.8 版本引入的新特性,它可以让你在函数组件中使用 state 以及其他 React 特性。在此之前,只有 class 组件才能使用这些功能。Hooks 的引入,使得我们可以在不使用类的情况下构建 React 应用程序。
二、 Hooks 解决了什么问题
-
组件复用状态逻辑的问题
之前,我们通常会在生命周期函数中编写代码逻辑,而生命周期函数难以进行复用。Hooks 则可以把这些逻辑抽离到一个可复用的函数中。 -
大型组件难以理解
React 组件越来越大,代码逻辑就会变得难以理解和维护。Hooks 通过将相关逻辑分割到更小的函数中,使代码更加清晰易懂。 -
难以理解的 class
对于一些开发人员来说,在 JavaScript 中理解 class 并不是一件容易的事情。Hooks 完全使用函数,让开发人员更容易理解React组件。
三、常见的Hooks有哪些
- useState:用于声明状态变量
- useEffect:用于处理组件的副作用
- useContext:用于订阅 React 上下文
- useReducer:用于管理组件状态
- useCallback:用于缓存函数
- useMemo:用于缓存计算结果
- useRef:用于创建可变的 ref 对象
- useImperativeHandle:用于自定义暴露给父组件的实例值
- useLayoutEffect:与 useEffect 相同,但是会在所有DOM改变之后同步触发
- useDebugValue:用于在 React 开发工具中显示自定义 hook 的标签
总的来说,Hooks 让我们在函数组件中也能使用 state 以及其他 React 特性,提高了组件逻辑复用性,同时使代码更加清晰易懂。
四、10种核心Hooks用法和使用场景
- useState
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0); // 声明状态变量及其setter函数
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
- 使用场景: 在函数组件中管理状态,如计数器、表单控件等。
- 注意事项:
useState
只接受一个参数作为初始状态- 状态更新会引起组件重新渲染,因此避免在主体渲染中调用
setState
- 可以使用多个
useState
管理不同状态
- useEffect
import React, { useState, useEffect } from 'react';
function Example() {
const [data, setData] = useState([]);
useEffect(() => {
// 模拟网络请求
const fetchData = setTimeout(() => {
setData([1, 2, 3]);
}, 2000);
// 清理副作用
return () => clearTimeout(fetchData);
}, []); // 空数组确保只运行一次
return <ul>{data.map(item => <li key={item}>{item}</li>)}</ul>;
}
- 使用场景: 执行有副作用的操作,如发送网络请求、订阅事件等。
- 注意事项:
- 第二个参数是一个数组,用于指定effect的依赖项,只有依赖项变化时才会重新执行
- 返回一个清理函数,用于清理副作用,如取消订阅等
- 空数组
[]
表示只在组件挂载和卸载时执行
- useContext
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>I am styled by theme context!</button>;
}
- 使用场景: 跨层级组件传递数据,避免手动逐层传递 props。
- 注意事项:
- 需要先使用
createContext
创建Context对象 - 上层组件使用
Provider
提供数据 - 下层组件使用
useContext
获取数据
- 需要先使用
- useReducer
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
- 使用场景: 状态逻辑较复杂时,可以使用 Reducer 模式优化状态管理。
- 注意事项:
useReducer
接收两个参数,第一个是reducer函数,第二个是初始状态- reducer函数根据不同的action决定如何更新状态
dispatch
用于发送action从而更新状态
- useCallback
import React, { useState, useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<input value={name} onChange={e => setName(e.target.value)} />
<Child handleClick={handleClick} />
<p>Count: {count}</p>
</div>
);
}
const Child = React.memo(({ handleClick }) => {
console.log('Child rendered');
return <button onClick={handleClick}>Click me</button>;
});
- 使用场景: 缓存函数实例,避免组件重新渲染时重复创建函数实例。
- 注意事项:
- 第二个参数是一个数组,用于指定依赖项,只有依赖项变化时才会重新创建函数实例
- 通常与
React.memo
或shouldComponentUpdate
一起使用,提高性能
- useMemo
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const data = useMemo(() => {
return { count, name };
}, [count, name]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<input value={name} onChange={e => setName(e.target.value)} />
<Display data={data} />
</div>
);
}
function Display({ data }) {
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
- 使用场景: 缓存计算结果,避免重复计算。
- 注意事项:
- 第二个参数是一个数组,用于指定依赖项,只有依赖项变化时才会重新计算
- 如果计算量非常小,使用可能引起额外开销,适合使用在计算量较大的场景
- useRef
import React, { useRef, useEffect } from 'react';
function App() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<div>
<input ref={inputRef} type="text" />
</div>
);
}
- 使用场景: 获取DOM元素或保存可变值的引用。
- 注意事项:
useRef
返回一个可变的ref对象,其current
属性被初始化为传入的参数- ref对象在组件的整个生命周期内保持不变
- useImperativeHandle
import React, { useRef, forwardRef, useImperativeHandle } from 'react';
const Input = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
}));
return <input ref={inputRef} {...props} />;
});
const App = () => {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<Input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
};
- 使用场景: 使父组件可以获取子组件实例的句柄,调用子组件的方法。
- 注意事项:
- 需要配合
forwardRef
来使用 - 父组件通过ref获取子组件实例,子组件通过
useImperativeHandle
定义暴露给父组件的方法
- 需要配合
- useLayoutEffect
import React, { useLayoutEffect, useState } from 'react';
function App() {
const [value, setValue] = useState(0);
useLayoutEffect(() => {
if (value === 0) {
setValue(10 + Math.random() * 200);
}
}, [value]);
console.log('render', value);
return (
<div onClick={() => setValue(0)}>
Value: {value}
</div>
);
}
- 使用场景: 在DOM更新后立即执行一些同步操作,例如获取DOM元素位置等。
- 注意事项:
- 与
useEffect
的执行时机不同,useLayoutEffect
会在所有DOM变更之后同步执行
-如果操作非常昂贵,应该考虑使用useEffect
以免阻塞浏览器渲染
- 与
- useDebugValue
import React, { useDebugValue, useState } from 'react';
function useCustomHook(initialValue) {
const [value, setValue] = useState(initialValue);
useDebugValue(`Current value: ${value}`);
return [value, setValue];
}
function App() {
const [value, setValue] = useCustomHook(0);
return (
<div>
<p>Value: {value}</p>
<button onClick={() => setValue(value + 1)}>Increment</button>
</div>
);
}
- 使用场景: 在 React 开发者工具中显示自定义 Hook 的标签,方便调试。
- 注意事项:
- 只在开发环境下有效,生产环境会被自动忽略
- 第一个参数是一个格式化的字符串,用于显示标签内容
以上是一些常用 Hooks 的示例代码、使用场景和注意事项。在实际开发中,应根据具体需求合理选择和组合使用 Hooks,以提高代码的可读性和可维护性。同时也要注意 Hooks 的使用规则和限制,避免出现潜在的问题。
版权声明:本文标题:React 函数组件开发必备:十大常用 Hooks 使用指南 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1727957086a1139516.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论