一、基本介绍
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
- 不用
Hook
的劣势
>Hook 出现之前,组件之间复用状态逻辑很难,解决方案(HOC、Render Props)都需要重新组织组件结构, 且代码难以理解。
>在React DevTools 中观察过 React 应用,你会发现由 providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”。
>组件维护越来越复杂,譬如事件监听逻辑要在不同的生命周期中绑定和解绑,复杂的页面componentDidMount包涵很多逻辑,代码阅读性变得很差。
>class组件中的this难以理解,且class 不能很好的压缩,并且会使热重载出现不稳定的情况。
- 使用
Hook
的优势
1. 避免地狱式嵌套,可读性提高。
2. 函数式组件,比class更容易理解。
3. class组件生命周期太多太复杂,使函数组件存在状态。
4. 解决HOC和Render Props的缺点。
5. UI 和 逻辑更容易分离。
核心实现
- 回顾闭包
闭包是一个特殊的对象
它由两部分组成,执行上下文A以及在A中创建的函数B。
当B执行时,如果访问了A中的变量对象,那么闭包就会产生。
定义一个React组件,并且在其他模块中使用,让我们看看和闭包有什么关系
- 在文件
Counter.jsx
中定义一个Counter
组件
// Counter.jsx
export default function Counter() {}
- 然后在
App
模块中使用Counter
组件
// App.jsx
import Counter from './Counter';
export default function App() {
// todo
return (
<Counter />
)
}
- 上面的代码我们可以手动转换成伪代码
const CounterModule = (function() {
return function Counter() {}
})()
const AppModule = (function() {
const Counter = CounterModule;
return function App() {
return Counter();
}
})()
/*
当App在render中执行时,访问了AppModule中的变量对象(定义了变量Counter),那么闭包就会产生。
所以,闭包跟模块之间的关系,到这里,就非常清晰了。
根据闭包的生成条件与实践场景,我们会发现,模块中,非常容易生成闭包。
每一个JS模块都可以认为是一个独立的作用域,当代码执行时,该词法作用域创建执行上下文,
如果在模块内部,创建了可供外部引用访问的函数时,就为闭包的产生提供了条件,只要该函数在外部执行访问了模块内部的其他变量,闭包就会产生
*/
- 此处案例中的useState的实现原理与用法,与React Hooks基本一致。
- 但是真正的源码实现肯定不会这么简单粗暴。
- 定义一个名为State的模块,代码如下:
// state.js
let state = null;
export const useState = (value: number) => {
// 第一次调用时没有初始值,因此使用传入的初始值赋值
state = state || value;
function dispatch(newValue) {
state = newValue;
// 假设此方法能触发页面渲染
render();
}
return [state, dispatch];
}
- 在其他模块中引入并使用。
import React from 'react';
import {useState} from './state';
function Demo() {
// 使用数组解构的方式,定义变量
const [counter, setCounter] = useState(0);
return (
<div onClick={() => setCounter(counter + 1)}>hello world, {counter}</div>
)
}
export default Demo();
/*
执行上下文state(模块state)以及在state中创建的函数useState
当useState在Demo中执行时,访问了state中的变量对象,那么闭包就会产生。
根据闭包的特性,state模块中的state变量,会持久存在。
因此当Demo函数再次执行时,我们也能获取到上一次Demo函数执行结束时state的值
这就是React Hooks能够让函数组件拥有内部状态的基本原理
*/