哈哈哈?,借用某某某的话。。。
- 你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗
——拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function。 - 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗?
——拥有了Hooks,生命周期钩子函数可以先丢一边了。 - 你在还在为组件中的this指向而晕头转向吗?
——既然Class都丢掉了,哪里还有this?你的人生第一次不再需要面对this
这样说来,你是不是就会对他很感兴趣。
首先来一个最简单的例子
- 简单的有状态组件
import React from 'react';
class Index extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
export default Index
- hooks实现的组件
import React,{ useState } from 'react';
function Index() {
const [count, setCount] = useState(0); // 1.
return (
<div>
<p>You clicked {count} times</p> //2.
<button onClick={() => setCount(count + 1)}> //3.
Click me
</button>
</div>
);
}
export default Index;
从行数上来说,是不是少了一些。可以看到Index变成了一个函数,但这个函数却又自己的状态(count),同时他嗨可以更新自己的状态(setCount),之所以这么厉害,是因为它注入了一个hook–useState,就是hook让我们的函数变成一个有状态的函数。
除此之外还有其他特性,我们一起来了解吧。
什么是State Hooks?
我们来看看上面的简单例子,可以从三个步骤开看
- 申明一个状态变量
const [count, setCount] = useState(0); //运用的是数组结构
useState是react自带的一个hook函数,它的作用就是用来申明变量。useState这个函数接受的参数使我们状态的初始值。他返回的是一个数组,第[0]项是当前的状态值,第[1]项是改变当前状态的函数方法。总结来说,就是useState申明了一个状态变量count,把他的初始值设置为0,同时还提供了一个更好count的函数setCount。
- 读取状态
<p>You clicked {count} times</p>
这个就很简单,因为count就只是一个单纯的变量而已,就不需要写成{this.state.count}这种方式了
3. 更新状态
<button onClick={() => setCount(count + 1)}>
Click me
</button>
当我们点击按钮的时候,会调用setCount这个方法,这个方法修改过的参数是修改过的新状态值。接下就交给react了,他会帮我们重新渲染Index这个组件,并且使用的是更新后的新状态。接下来的一个思考,为什么他能记住之前的状态呢。。。
Effect Hooks?
我们先对上面的例子进行改造
类组件写法:
import React from 'react';
class Index extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return (
<div>
<Home/>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
export default Index
hooks写法:
import React,{ useState ,useEffect} from 'react';
function Index() {
const [count, setCount] = useState(0);
useEffect(() => {
// 更新文档的标题
document.title = `点击${count}次`;
})
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Index;
我们写的有状态的组件,通常会产生很多副作用,比如发起ajax请求获取数据,添加一些监听的注册和取消注册,手动修改dom等等。我们之前都把这些副作用的函数写在生命周期函数钩子里,比如componentDidMount,componentDidUpdate和componentWillUnmount。而现在的useEffect就相当与这些声明周期函数钩子的集合体。它以一抵三。
这里要注意几点:
第一,react首次渲染和之后的每次渲染都会调用一遍传给useEffect的函数。而之前我们要用两个声明周期函数来分别表示首次渲染(componentDidMount),和之后的更新导致的重新渲染(componentDidUpdate)。
第二,useEffect中定义的副作用函数的执行不会阻碍浏览器更新视图,也就是说这些函数是异步执行的,而之前的componentDidMount或componentDidUpdate中的代码则是同步执行的。这种安排对大多数副作用说都是合理的,但有的情况除外,比如我们有时候需要先根据DOM计算出某个元素的尺寸再重新渲染,这时候我们希望这次重新渲染是同步发生的,也就是说它会在浏览器真的去绘制这个页面前发生
- 怎么跳过一些不必要的副作用函数
每次重新渲染都要执行一遍这些副作用函数,显然是不经济的。怎么跳过一些不必要的计算呢?我们只需要给useEffect传第二个参数即可。用第二个参数来告诉react只有当这个参数的值发生改变时,才执行我们传的副作用函数(第一个参数)。
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 只有当count的值发生变化时,才会重新执行`document.title`这一句
还有哪些自带的Effect Hooks?
useContext
useReducer
useCallback
useMemo
useRef
useImperativeMethods
useMutationEffect
useLayoutEffect