在react16.8版本之后,由于hooks的出现,函数组件得到了扩展,完全不使用"类",就能写出一个全功能的组件。
React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。
useState()
用于为函数组件引入状态(state)
。纯函数不能有状态,所以把状态放在钩子里面。
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量,初始值为0,后续通过setCount改变它能让视图重新渲染
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useState()
函数接受状态的初始值,作为参数。该函数返回一个数组,数组的第一个元素是一个变量(上例是count
),指向状态的当前值。第二个元素是一个函数(上例是setCount
),用来更新该状态,约定是set前缀加上状态的变量名
useState
让函数组件也可以有state
状态, 并进行状态数据的读写操作const [xxx, setXxx] = useState(initValue)
useState()
说明:
setXxx()
2种写法:
setXxx(newValue)
: 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值setXxx(value => newValue)
: 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值useEffect()
用来引入具有副作用的操作,最常见的就是向服务器请求数据。以前,放在componentDidMount
里面的代码,现在可以放在useEffect()
。
useEffect(() => {
// Async Action
}, [dependencies])
上面用法中,useEffect()
接受两个参数。第一个参数是一个函数,异步操作的代码放在里面。第二个参数是一个数组,用于给出 Effect
的依赖项,只要这个数组发生变化,useEffect()
就会执行。
只要是副作用(side effect)
,都可以使用useEffect()
引入。它的常见用途有下面几种。
可以把useEffect
看做如下三个生命周期的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
useEffect()
允许返回一个函数,在组件卸载时,执行该函数,清理副作用。如果不需要清理副作用,useEffect()
就不用返回任何值。
React.useEffect(()=>{
let timer = setInterval(()=>{
setCount(count => count+1 )
},1000)
return ()=>{
clearInterval(timer)
}
},[])
如上例,useEffect()在
组件加载时设置了一个定时器,并且返回一个清理函数,在组件卸载时清空定时器。
此处相当于执行了componentWillUnmount()
生命周期钩子。
useEffect()
[]
,相当于没有依赖,只会在组件挂载时执行一次useEffect()
,相当于componentDidMount()
生命周期钩子[x,xxx]
,数组内的变量为依赖,当依赖发生变化时,都会执行useEffect()
,相当于componentDidUpdate()
生命周期钩子使用useEffect()
时,有一点需要注意。如果有多个副效应,应该调用多个useEffect()
,而不应该合并写在一起。
function App() {
const [varA, setVarA] = useState(0);
const [varB, setVarB] = useState(0);
useEffect(() => {
const timeout = setTimeout(() => setVarA(varA + 1), 1000);
return () => clearTimeout(timeout);
}, [varA]);
useEffect(() => {
const timeout = setTimeout(() => setVarB(varB + 2), 2000);
return () => clearTimeout(timeout);
}, [varB]);
return <span>{varA}, {varB}</span>;
}
useReducers()
钩子用来引入 Reducer
功能。
用法: const [state, dispatch] = useReducer(reducer, initialState);
它接受 Reducer
函数和状态的初始值作为参数,返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送 action
的dispatch
函数。
下面是一个计数器的例子。用于计算状态的 Reducer
函数如下。
const myReducer = (state, action) => {
switch(action.type) {
case('countUp'):
return {
...state,
count: state.count + 1
}
default:
return state;
}
}
组件代码如下
function App() {
const [state, dispatch] = useReducer(myReducer, { count: 0 });
return (
<div className="App">
<button onClick={() => dispatch({ type: 'countUp' })}>
+1
</button>
<p>Count: {state.count}</p>
</div>
);
}
useRef
返回一个可变的 ref
对象,其 current
属性被初始化为传入的参数initialValue
。
写法:const refContainer = useRef(initialValue);
用法与createRef()
一致
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}