在上一章,我们粗略的讲解了一个简单的Hook useState 现在我们详细看下常用的Hook的内容。
1. useState
以下就是用得最多的例子,也最容易清楚理解。
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
声明一个count变量,使用useState 组件中有按钮,其点击事件为useState更新它的函数setCount。
Hook 是什么? Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,
useState是允许你在 React 函数组件中添加 state 的 Hook
什么时候我会用 Hook? 如果你在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将其它转化为 class。现在你可以在现有的函数组件中使用 Hook。
我们在class组件中在构造函数中设置 this.state 为 { count: 0 } 来初始化 count state 为 0
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
在函数组件中,我们没有 this,所以我们不能分配或读取 this.state。我们直接在组件中调用 useState Hook
const [count, setCount] = useState(0);
回到这个方括号
等号左边名字并不是 React API 的部分,你可以自己取名字 我们也可以声明其他的变量
const [name, setName] = useState('ms');
使用useState返回的更新变量的函数进行数据变化。
2. useEffect
Effect Hook 可以让你在函数组件中执行副作用操作 根据上一个计步器例子,进行学习。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。不管你知不知道这些操作,或是“副作用”这个名字,应该都在组件中使用过它们
通俗来讲如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
在 React 组件中有两种常见副作用操作:需要清除的和不需要清除的。那就需要进行下一步的学习。
- 不需要清除副作用
有时候,我们只想在 React 更新 DOM 之后运行一些额外的代码。 比如发送网络请求,手动变更 DOM,记录日志,这些都是常见的无需清除的操作。因为我们在执行完这些操作之后,就可以忽略他们了
使用useEffect,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它
- 需要清除副作用
我们研究了如何使用不需要清除的副作用,还有一些副作用是需要清除的。例如订阅外部数据源。这种情况下,清除工作是非常重要的,可以防止引起内存泄露
下面我们根据官方文档的例子来进行class和Hook之间的区别假设有一个ChatAPI我们从外部引入组件。允许我们订阅好友的在线状态。通常会在 componentDidMount 中设置订阅,并在 componentWillUnmount 中清除它
class FriendStatus extends React.Component {
constructor(props) {
super(props);
this.state = { isOnline: null };
this.handleStatusChange = this.handleStatusChange.bind(this);
}
componentDidMount() {
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}
handleStatusChange(status) {
this.setState({
isOnline: status.isOnline
});
}
render() {
if (this.state.isOnline === null) {
return 'Loading...';
}
return this.state.isOnline ? 'Online' : 'Offline';
}
}
使用useEffectHook
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return function cleanup() { //清除机制
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
effect具有可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。
简单用法就是这样。
但是有问题了,useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后and每次更新之后都会执行。你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。
- 使用 Effect 的提示
跟useState一样,两个无相关联的逻辑可以使用多个useEffectHook
useEffect(() => {
document.title = `You clicked ${count} times`;
});
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return function cleanup() { //清除机制
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
Hook 允许我们按照代码的用途分离他们, 而不是像生命周期函数那样。React 将按照 effect 声明的顺序依次调用组件中的每一个 effect
-
通过跳过 Effect 进行性能优化
根据上述React 将按照 effect 声明的顺序依次调用组件中的每一个effect。比如组件重新渲染时候count没有发生了改变,但是useEffect按照顺序下来还是会调用。我们可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
基本用法,知识介绍到这里,还有不足之处。还是请各位观看官方文档