Hoooks:
. Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
. 使用 Hook 其中一个目的就是要解决 class 中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题。
1、useState:
const [count, setCount] = useState(0)
count:变更名
setCount:更新方法:
setCount(count + 1)
//或者
setState(item => {
return {item + 1};
});
惰性初始 state
const [state, setState] = useState(() => {
// 组件的初始渲染中起作用,有些需求要在初始时做复杂的计算做为state初始值。
return count + counts + 10;
});
问:
React 怎么知道 useState 对应的是哪个组件,因为我们并没有传递 this 给 React。(更新数据时都会调用一次组件,也就是会再执行一次函数组件,那么count值为什么可以保存上次的呢?)
解:
React 保持对当先渲染中的组件的追踪,每个组件内部都有一个「记忆单元格」
列表。它们只不过是我们用来存储一些数据的 JavaScript 对象。当你用 useState() 调用一个 Hook 的时候,它会读取当前的单元格(或在首次渲染时将其初始化),然后把【指针】
移动到下一个。这就是多个 useState() 调用会得到各自独立的本地 state 的原因。
个人理解:闭包(因为组件都被「记忆单元格」【指针】引入了)。
函数组件也是一个闭包
,其中定义的count变量做为闭包私有变量会被useState中强引用,而等到数据更新再次执行函数组件时,会把强引用变量值给到相同变量名。
2、useEffect :
useEffect( () => {} )
说明:
1.
useEffect会在第一次渲染及【每次更新】后延迟执行
。
2.
useEffect可当做componentDidMount(挂载完成),componentDidUpdate(更新完成) 和 componentWillUnmount(组件卸载前) 这三个生命周期函数的组合。
3.
与 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。
4.
useEffect的参数为一个函数(异步)
,React 会保存这个函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它(闭包机制)。
## 需要清除的 effect:componentWillUnmount(组件卸载前)在哪做? ##
为保持代码的紧密性
,所以 useEffect 的设计是在同一个地方执行。如果你的 effect 返回一个函数
,React 将会在执行清除操作时调用它:
useEffect( () => { return () => {//这里做需要清除的事件} } )
Effect性能优化:
在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。
在 class 组件中
在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决:
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) { //如果state中count值有变化,那么就更新document.title
document.title = `You clicked ${this.state.count} times`;
}
}
在函数组件中
在函数组件中,设置useEffect 的第二个可选参数即可解决:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新document.title
useEffect(()=>{
console.log('useEffect第二个参数为[]时,当前函数仅在组件挂载和卸载时执行');
return () => {
console.log('我要被销毁了');
}
},[]) // useEffect第二个参数为[]时,当前函数仅在组件挂载和卸载时执行
3、createContext(挂载) & useContext(解析)
useContext类似props
1、创建一个 React 的 上下文 createContext
const MyContext = React.createContext(defaultValue) //defaultValue 是传入的默认值。
//如果匹配不到最新的 Provider 则会使用默认值,默认值一般只有在对组件进行单元测试(组件并未嵌入到父组件中)的时候,比较有用。
2、父组件引入了实例,并且通过 MyContext.Provider 将子组件包装,并且通过 Provider的value 将父组件方法提供出去。
<MyContext.Provider value={{ setStep }}>
<子组件 />
</MyContext.Provider>
3、子组件通过useContext解析父组件提供的方法,从而达到子组件中可调用及修改父组件的方法和state。
const { setStep } = useContext(MyContext);
useReducer:
1、useState
的替代方案。
2、useReducer
会比 useState
更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer
还能给那些会触发深更新的组件做性能优化,因为[你可以向子组件传递 dispatch
而不是回调函数
Hook 规则:
1. 只在最顶层使用 Hook,不要在循环,条件或嵌套函数中调用 Hook
2. 只在 React 的函数组件中调用 Hook,不要在普通的 JavaScript 函数中调用 Hook。
3. Hook 规则插件来强制执行上两条规则:
npm install eslint-plugin-react-hooks --save-dev
// 你的 ESLint 配置
{
"plugins": [
// ...
"react-hooks"
],
"rules": {
// ...
"react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
"react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
}
}