React Hooks 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
前言
本篇主要以讲几个常用的api为主。
1.useState
这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加,现在我们的写法如下,
class Example 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>
);
}
}
这是我们所熟悉的写法,替换成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>
);
}
- 1.首先通过在函数组件里调用useState()来给组件添加一些内部 state,(React 会在重复渲染时保留这个 state)。
- 2.useState()可以传入一个参数,传入的参数就是初始的state,在上面例子当中,0就是初始值。【这个初始 state 参数只有在第一次渲染的会被用到。】
- 3.useState() 会返回一对值:当前状态和一个让你更新它的函数(你可以在事件处理函数中或其他一些地方调用这个函数,它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并。)
- 4.可以通过useState声明多个state变量,如下
function ExampleWithManyStates() {
// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
// ...
}
2.useEffect
useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
依然是先上例子
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
document.title = `You clicked ${this.state.count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
-
1.默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。
-
2.副作用函数还可以通过返回一个函数来指定如何“清除”副作用。它的执行顺序是,每次页面更新前,先执行return的函数,然后在执行useEffect里面的内容。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`You clicked ${count} times`);
return () => {
console.log('每次页面更新前,我会先被执行');
}
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
- 3.跟 useState 一样,你可以在组件中多次使用 useEffect,因此通过使用 Hook,你可以把组件内相关的副作用组织在一起(例如创建订阅及取消订阅),而不要把它们拆分到不同的生命周期函数里。
- 4.useEffect还可以传入第二个参数,指定当某个值发生变化的时候,才触发副作用.
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
- 5.如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。
3.useReducer
useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
// reducer.js
export const initialState = {count: 0};
export default (state, action) => {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
// Counter.js
import React, { useReducer } from 'react';
import reducer, { initalState } from './reducer.js';
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</div>
);
}
4.useContext
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。
具体使用查看这篇文章。