React Hooks是 React v16.8 新增特性。本文假设您对 Hooks 有一个基本的理解, 你应该读过 Hook 简介 ,并且运行过里面例子中的代码。以下我们将列举和总结一些 React Hooks 使用的注意点。
一、Hook 规则
Hook 规则 中提到:
只在最顶层使用 Hook,不要在循环,条件或嵌套函数中调用 Hook
React 靠的是 Hook 调用的顺序。因为我们的示例中,Hook 的调用顺序在每次渲染中都是相同的,所以它能够正常工作。
下面是把 useState 放在 if 条件语句中,运行直接被拒绝,即使没有不被允许,我们也不该这么写。
import React, { useState } from 'react';
function Count (){
const [count,setCount] = useState(0);
if (true){
const [count1,setCount1] = useState(0);
}
return (
<div>
<p>you click {count} times</p>
<button onClick={()=>{setCount(count+1)}}>点击</button>
</div>
)
}
export default Count;
运行结果如下图
二、Effect Hook 的使用
Effect Hook 用于替换生命周期挂钩,如 componentDidMount、 componentDidUpdate 和 componentWillUnmount。
useEffect 接收两个参数,第一个是匿名函数,在 React 组件渲染后执行。第二个参数为可选,接收的是依赖组成的数组,要有数组内的某一元素更改,才执行该 effect 。
useEffect 第一个参数中的匿名函数可以有返回值,返回值是一个函数,这个函数会在下一个 effect 执行之前调用。
import React, { useState,useEffect } from 'react';
function Effect (){
const [count,setCount] = useState(0);
useEffect(()=>{
console.log(`useEffect count = ${count} `);
return ()=>{ console.log(`count effect return pre count ${count}`)}
},[count]);
return (
<div>
<p>
you click {count} timesss
</p>
<button onClick={()=>{setCount(count+1)}}>点击</button>
</div>
)
}
export default Effect;
执行以上代码:
1、useEffect 不传第二个参数时,匿名函数会在组件每次渲染后都执行一遍。
useEffect(()=>{
console.log(`render`);
});
2、useEffect 的第二个参数传入的是空数组时,该 effect 只在组件第一次加载后执行,这个与 Component 中的 componentDidMount 对应。返回值则会在组件卸载前执行,与 componentWillUnmount 对应。
useEffect(()=>{
console.log(`componentDidMount`);
return ()=>{ console.log(`componentWillUnmount`); }
},[]);
3、useEffect 第一个参数中的匿名函数的返回值一般被用来做一些清除工作。
就如我们在 componentDidMount 中设置订阅,并在 componentWillUnmount 中清除它。我们可以查看 官网中使用 Hook 的示例。那假如我们要在组件卸载时清除订阅,可以在依赖项( useEffect 的第二个参数)加上一个空数组。
我们借助 react-router 来看看组件加载、更新和卸载时 useEffect 的工作。看代码
import React, { useState,useEffect } from 'react';
import {BrowserRouter as Router,Route,Link} from "react-router-dom"
function Count (){
const [count,setCount] = useState(0);
useEffect(()=>{
console.log(`Count useEffect current ${count}`);
return ()=>{console.log(`count useEffect return pre ${count}`);}
},[count]);
useEffect(()=>{
console.log(`Count []`);
return ()=>{console.log(`Count [] return`);}
},[]);
return (
<div>
<p>you click {count} times</p>
<button onClick={()=>{setCount(count+1)}}>点击</button>
</div>
)
}
function Component2 (){
useEffect(()=>{
console.log("Component2 []");
return ()=>{console.log("Component2 [] return");}
},[])
return (<h2>Component2</h2>)
}
function Effect (){
return (
<div>
<Router>
<ul>
<li><Link to="/count">计数器</Link></li>
<li><Link to="/component2">组件2</Link></li>
</ul>
<Route path="/count" exact component={Count} />
<Route path="/component2" component={Component2} />
</Router>
</div>
)
}
export default Effect;
运行,我们可以看到如下的操作和打印:
1、点击 计数器 ,加载 Count 组件,两个 effect 都执行并打印。
2、点击按钮,先执行上一个 effect 返回的函数,所以先打印 ”count useEffect return pre 0“ 。接着执行 此次 effect 函数,打印 “Count useEffect current 1”。以此类推。
3、点击 组件2 ,打印了 “count useEffect return pre 3” 和 “Count [] return”。说明 Count 组件在卸载前,所有的 effect 都执行了 return 函数。接着打印 “Component2 []”, 组件 Component2 加载完成。
4、点击 计数器 , 打印 “Component2 [] return” 、“Count useEffect current 0” 、“Count []”,这个过程的分析与上面一致,不在赘述。
至此,Effect Hook 先告一段落。
三、useContext 共享状态勾子
在此之前,希望您有看过,React官网 useContext 简介 和 React官网 useReducer 简介 中的内容,因为以下例子是两者的结合。
接下来我们使用 createContext 创建一个ColorContext,然后使用 Context.Provider 共享数据。使用 useReducer 分发状态。
我们看到父组件 Color.js 的代码,value 值是color和dispatch,真正要共享的值是color,dispatch也被共享是因为子组件要用它来改变color的值。
import React, { createContext ,useReducer} from 'react';
const ColorContext = createContext({});
const UPDATE_COLOR = "UPDATE_COLOR";
const reducer = (state,action)=>{
switch (action.type){
case UPDATE_COLOR:
return action.color;
default :
return state;
}
}
const Color = (props)=>{
const [color,dispatch] = useReducer(reducer,"blue");
return (
<ColorContext.Provider value = {{color,dispatch}}>
{props.children}
</ColorContext.Provider>
)
}
export {
ColorContext,
Color,
UPDATE_COLOR
}
创建要共享父组件状态的子组件,通过 useContext 和之前创建的 ColorContext 获取共享值Color。
import React,{useContext} from 'react';
import {ColorContext} from "./Color"
function ShowArea (){
const {color} = useContext(ColorContext);
return (
<div style={{color:color}}>
现在是{color}色
</div>
)
}
export default ShowArea;
创建能改变共享状态的子组件,通过 useContext 和之前创建的 ColorContext 获取 useReducer 函数返回的 dispatch(这个 dispatch 也是共享值)。
import React, { useContext } from 'react';
import {ColorContext,UPDATE_COLOR} from "./Color";
function Buttons (){
const {dispatch} = useContext(ColorContext);
return (
<div>
<button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"red"})}}>红色</button>
<button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"yellow"})}}>黄色</button>
</div>
)
}
export default Buttons;
最后的使用是这样的:
import React, { Component } from 'react';
import ShowArea from './ShowArea';
import Buttons from './Buttons';
import {Color} from "./Color";
function ContextReducer (){
return (
<div>
<Color>
<ShowArea/>
<Buttons/>
</Color>
</div>
)
}
export default ContextReducer;
我们来看看运行情况:
如果看完觉得对您有帮助,还有劳点个赞,谢谢啦。
参考文章 (感谢)
React官网 Hook 简介
React Hooks 视频教程_技术胖
React Hooks — How To Use useState and useEffect Example