React在版本16.8中引入钩子。钩子使我们能够创建具有状态和副作用的功能组件。
useEffect
钩可帮助您在功能组件中创建副作用。
此钩将函数作为第一个参数和数组依赖性作为第二个参数。
效果必须在功能的正文中。如果您的效果需要清理,则可以返回函数执行它。
hook
function App() {
const [count, setCount] = useState(0);
const [timer, setTimer] = useState(false);
const handleIncrease = () => setTimer((prevState) => !prevState);
useEffect(() => {
let timer1 = setTimeout(() => setCount((prevcount) => prevcount + 1), 2000);
return () => {
clearTimeout(timer1);
};
}, [timer]);
return (
<div>
<p>count : {count}</p>
<button onClick={handleIncrease} type="button">
Launch Timer
</button>
</div>
);
}
在这里,我们有一个钩子的示例。它执行一个计时器,该计时器将计数状态增加1。我们使用超时函数,这就是为什么我们需要清理功能来清除它。
数组依赖关系包含状态timer
。我们使用它来触发useEffect
。
每次在我们的组件中更新状态时,它都会重新启动。如果timer
已更新,则执行useEffect
内部的功能。
当组件也卸下时,我们的清理功能将执行,以避免内存泄漏。
数组依赖性
使用数组依赖关系,我们可以选择钩中内部的函数执行何时。
在每个Rerender
要在安装座和每个rerender处执行它,请跳过数组依赖。
在山上
有一个空数组依赖性,只有在组件安装时才能执行您的效果。
在更新
每次更新数组依赖项中的值,在安装座时,挂钩将运行。
更多使用效果示例
现在,我们已经涵盖了useEffect
钩的基础知识,让我们看一些如何使用它的示例。
从API获取数据
useEffect
挂钩的一种常见用例是从API获取数据。
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
setLoading(false);
}
fetchData();
}, [userId]);
if (loading) {
return <Loading />;
}
return <Profile user={user} />;
}
我们使用useEffect
挂钩在组件安装或userId
prop更改时获取给定userId
的用户数据。
我们在获取数据时将loading
状态设置为true
,然后在收到数据后将其更新为false
。
这使我们可以在获取数据时显示加载指示器,然后在数据可用后显示用户配置文件。
设置订阅
useEffect
挂钩也可用于设置订阅,例如事件侦听器或Web套接字连接。
function Chat({ userId, onMessage }) {
useEffect(() => {
const socket = new WebSocket(`wss://chat.example.com/${userId}`);
socket.addEventListener('message', onMessage);
return () => {
socket.removeEventListener('message', onMessage);
socket.close();
};
}, [userId, onMessage]);
// ...
}
在此示例中,我们使用useEffect
挂钩来设置Web套接字连接和事件侦听器来传入消息。
useEffect
钩子还包括一个清理功能,该功能可以删除事件侦听器并在组件卸下时关闭套接字连接。
添加事件听众
useEffect
挂钩也可以用来将事件侦听器添加到DOM。
function WindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<div>
Window size: {size.width} x {size.height}
</div>
);
}
在此示例中,我们使用useEffect
钩将resize
事件添加到页面上。在安装座时,可变大小的更新具有窗口的宽度和高度。当组件卸下时,清理功能会删除事件侦听器。
将使用效应与其他钩子相结合
useEffect
挂钩可以与其他钩子(例如useState
和useContext
)组合使用,以创建更复杂的逻辑。
例如,您可以使用useState
钩管理用于触发效果的状态:
function Form() {
const [submitting, setSubmitting] = useState(false);
useEffect(() => {
if (submitting) {
// perform submission logic
}
}, [submitting]);
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
<button type="submit" disabled={submitting}>
Submit
</button>
</form>
);
}
在此示例中,当submitting
状态为true
时,我们使用useEffect
钩执行提交逻辑。这使我们可以在提交表单时禁用提交按钮并显示加载指示器。
您还可以使用useContext
钩访问useEffect
钩中的上下文值:
function UserList({ userId }) {
const { users, dispatch } = useContext(UserContext);
useEffect(() => {
async function fetchUsers() {
const response = await fetch(`/api/users?id=${userId}`);
const data = await response.json();
dispatch({ type: 'ADD_USERS', users: data });
}
fetchUsers();
}, [userId, dispatch]);
// ...
}
在此示例中,我们使用useEffect
挂钩来获取基于userId
prop的用户列表,并派遣操作将用户添加到上下文状态。
您可以使用useRef
钩一次触发使用效果的内容。
function App() {
const trigger = useRef(false);
useEffect(() => {
if (trigger.current) return;
trigger.current = true;
// your logic here...
}, []);
// ...
}
在此示例中,在MOUNT上,将执行useEffect
的内容,并且trigger
将更新为true。现在,useEffect
的每个执行都将导致早期返回。
使用效果的最佳实践
使用useEffect
挂钩时要记住一些最佳实践:
- 注意效果的性能影响。避免使用过于频繁或计算昂贵的效果。
- 使用数组依赖性来控制何时运行效果。这可以有助于避免不必要的重新租赁并提高性能。
- 使用清理功能正确清理副作用,例如事件听众或网络请求。这可以帮助防止记忆泄漏。
- 使用
useCallback
钩记录以依赖关系到useEffect
钩的函数。这可以帮助避免不必要的重新租赁。 - 更喜欢较小的
useEffect
。他们更容易理解和维护。
陷阱和要注意的东西
使用useEffect
钩时有几件事要注意:
-
useEffect
挂钩不同步,这意味着您不应依靠其副作用在下一个渲染之前完成。 - 除非包含一个空数组依赖项,否则
useEffect
钩在初始渲染上不会运行。这意味着您不应使用useEffect
钩子来设置初始渲染中使用的状态。 - 请注意不要将值包括在数组依赖性中,以使变化过于频繁。这可能会导致
useEffect
挂钩运行太频繁,这可能会影响性能。
我希望这些信息有所帮助,并可以更好地了解React中的useEffect
钩!
这篇文章是关于与TypeScript的React基础知识的系列。在Twitter上查看或follow me查找下一步。
稍后再见!