我们大部分 React 类组件可以保存状态,而函数组件不能? 并且类组件具有生命周期,而函数组件却不能?
React 早期版本,类组件可以通过继承PureComponent来优化一些不必要的渲染,相对于函数组件,React 官网没有提供对应的方法来缓存函数组件以减少一些不必要的渲染,直接 16.6 出来的 React.memo函数。
React 16.8 新出来的Hook可以让React 函数组件具有状态,并提供类似 componentDidMount和componentDidUpdate等生命周期方法。
Hooks不会替换类,它们只是一个你可以使用的新工具。
Hooks的例子:
OneTimeButton 是函数组件,所做的事情就是当我们点击的时候调用 sayHi 方法函数组件
import React from 'react';
import {
render } from 'react-dom';
function OneTimeButton(props) {
return (
<button onClick={
props.onClick}>
点我
</button>
)
}
function sayHi() {
console.log('yo')
}
render(
<OneTimeButton onClick={
sayHi}/>,
document.querySelector('#root')
)
让这个组件做的是,跟踪它是否被点击,如果被点击了,禁用按钮,就像一次性开关一样。
但它需要一个state,因为是一个函数,它不可能有状态(React 16.8之前),所以需要重构成类。
class OneTimeButton extends React.Component {
state = {
clicked: false
}
handleClick = () => {
this.props.onClick();
// Ok, no more clicking.
this.setState({
clicked: true });
}
render() {
return (
<button
onClick={
this.handleClick}
disabled={
this.state.clicked}
>
You Can Only Click Me Once
</button>
);
}
}
使用 Hook 添加 State
用新的 useState hook向普通函数组件添加状态:
import React, {
useState } from 'react'
function OneTimeButton(props) {
const [clicked, setClicked] = useState(false)
function doClick() {
props.onClick();
setClicked(true)
}
return (
<button
onClick={
clicked ? undefined : doClick}
disabled={
clicked}
>
点我
</button>
)
}
useState是一个hook。 它的名字以“use”开头(这是Hooks的规则之一 - 它们的名字必须以“use”开头)。
useState hook 的参数是 state 的初始值,返回一个包含两个元素的数组:当前state和一个用于更改state 的函数。
类组件有一个大的state对象,一个函数this.setState一次改变整个state对象。
函数组件根本没有状态,但useState hook允许我们在需要时添加很小的状态块。 因此,如果只需要一个布尔值,我们就可以创建一些状态来保存它。
由于Hook以某种特殊方式创建这些状态,并且在函数组件内也没有像setState函数来更改状态,因此 Hook 需要一个函数来更新每个状态。 所以 useState 返回是一对对应关系:一个值,一个更新该值函数。 当然,值可以是任何东西 - 任何JS类型 - 数字,布尔值,对象,数组等。
Hooks 的特点
调用顺序规则 (它们每次必须以相同的顺序调用);
假设有以下这个组件:
function AudioPlayer() {
const [volume, setVolume] = useState(80);
const [position, setPosition] = useState(0);
const [isPlaying, setPlaying] = useState(false);
.....
}
它调用useState 3次,React 会在第一次渲染时将这三个 hook 放入 Hooks 数组中。
下次渲染时,同样的3个hooks以相同的顺序被调用,所以React可以查看它的数组,并发现已经在位置0有一个useState hook ,所以React不会创建一个新状态,而是返回现有状态。
这就是React能够在多个函数调用中创建和维护状态的方式,即使变量本身每次都超出作用域。
Hooks 的规则
自定义 hooks 函数只需要遵守规则 3 :它们的名称必须以“use”为前缀。
function AudioPlayer() {
// Extract these 3 pieces of state:
const [volume, setVolume] = useState(80);
const [position, setPosition] = useState(0);
const [isPlaying, setPlaying] = useState(false);
// < beautiful audio player goes here >
}
创建一个专门处理这些状态的新函数,并使用一些额外的方法返回一个对象,以便更容易启动和停止播放,例如:
function usePlayerState(lengthOfClip) {
const [volume, setVolume] = useState(80);
const [position, setPosition] = useState(0);
const [isPlaying, setPlaying] = useState(false);
const stop = () => {
setPlaying(false);
setPosition(0);
}
const start = () => {
setPlaying(true);
}
return {
volume,
position,
isPlaying,
setVolume,
setPosition,
start,
stop
};
}
这样提取状态的一个好处是可以将相关的逻辑和行为组合在一起。可以提取一组状态和相关事件处理程序以及其他更新逻辑,这不仅可以清理组件代码,还可以使这些逻辑和行为可重用。
通过在自定义hooks中调用自定义hooks,可以将hooks组合在一起。
hooks只是函数,当然,函数可以调用其他函数。
Hooks 提供了一种新的方式来处理React中的问题,其中的思想是很有意思且新奇的。