本文默认读者对 React Hooks 已经有必定的了解。 所以再也不赘述 Hooks API 的使用了, 还未了解的同窗能够去官网阅读React Hooks API Referencejavascript
使用 React Hooks 就不得不提到 React 函数组件。html
Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.java
从官网上的介绍来看, 组件就像 JavaScript 的函数, 它接收一些入参(props), 并返回 React 元素。react
在咱们最初学习使用 React 框架时, 首先了解的是经过Class
书写组件, 这样能够很好地理解并规划类组件
的数据与方法, 并且生命周期
可让咱们更清晰地了解组件的加载以及更新状态的触发时机。git
那函数组件
呢? 函数组件
自己解决了从数据到 React 元素的映射, 而Hooks
则在此基础上提供了数据存储以及 Side Effect(反作用)的处理。github
此时此刻, 让咱们忘记已经熟知的Class
与生命周期
, 来从新认识函数组件
+ Hooks
的 React。typescript
函数组件
是用来处理一些简单的 UI 组件, 经过 Props 传入的数据, 抽象封装一些组件。数组
function Header(props) {
const { title, description, avatar } = props;
return (
<div> <img src={avatar} /> <h1>{title}</h1> <p>{description}</p> </div> ); } 复制代码
限制了函数组件使用的缘由一方面在于它没有内部数据, 另外一方面就是没有生命周期, 所以没法实现具备必定交互与逻辑的功能。闭包
函数组件内定义的变量不是固化的, 执行完成后, 函数内的变量就会被清理掉了(非闭包状况)。因此, 咱们须要经过 Hooks 固化组件须要的一些数据。app
上面是 React Hooks 之 useState 的使用例子, 以下是浅尝辄止的理解:
经过
useState
, 咱们在某个地方定义了一个对象, 并挂载到某个不会让它消失的地方。useState
方法返回的第一个值就是咱们要的数据。useState
方法返回的第二个值是一个函数, 能够设置这个对象的值, 而后会触发函数从新渲染。
上面这坨话说的很模糊, 某个地方
究竟是哪一个地方, 定义了一个什么样的对象
, 又挂载到了什么地方。设置了新值后又是怎么触发渲染的???
在了解Hook
加载前仍是要了解一下 Hook 的定义和存储的。
下面是Hook
的 type 定义
export type Hook = {
// 数据
memoizedState: any,
// 下面这些暂时不须要了解
baseState: any,
baseQueue: Update<any, any> | null,
queue: UpdateQueue<any, any> | null,
// 链表下一个节点的指针
next: Hook | null,
};
复制代码
咱们须要了解的是Hook
是经过链表
存储的
第一个 Hook 会挂载到React Fiber Node
上, 以后在函数执行遇到的 Hook 会依次按顺序挂载到 Hook 节点后。
函数执行遇到的 Hooks 会按照顺序读取React Fiber Node
上的 Hook 节点。
如上图所示, 函数组件从新执行时是依赖 Hooks 队列的顺序的。若是在条件判断
中使用 Hook 就会让这个队列错乱。
所以也就会有以下官网提示:
Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.
反作用(Side Effect), 我的理解, 是在数据->视图
的转化过程当中, 出现的一些特别的时机
。咱们能够利用这些时机
去处理一些业务逻辑。
如下是使用useEffect
的一个简单的计数 Demo.
使用useEffect
去实如今渲染完成以后要去处理的一些事情。 你们也能够在官网的 API Reference 中找到 React useEffect 说明。
咱们能够经过流程图加深理解useEffect
这个 Hook。
以上是useEffect
Hook 的大体执行逻辑, 经过此图会发现useEffect
多了一步数据比对
的过程, 只有当如下条件成立时, SideEffect 才会触发调用。
咱们修改上面计数的例子就能够更好的理解两个 Hook。
function Demo(props) {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
useEffect(() => {
const timer = setTimeout(() => {
setCount(step + count);
}, 1000)
return () => {
clearTimeout(timer);
}
}, [count]);
return (
<div> <div>Count: {count}</div> <div>Step: {step}</div> <button onClick={() => { setCount(count + 1); }} > Click </button> </div>);
}
复制代码
在 Gif 图中, 在更新 Step 步长时, 计数第一次仍然是+1
, 随后才会+2
。
step
更新时, useEffect
的count
没有变化, 因此没有触发更新useEffect
触发时, 使用的是 Hook 中暂存的数据, 因此步长step
仍然是 1.咱们在 Hook 加载流程上补充上对比的过程。
Hook
中存入的是上一次渲染后的快照值, 因此在执行时, 也会使用上一次渲染留下来的值。
到这里, 咱们归纳下函数组件的渲染流程
本文只是提到了useState
, useEffect
这两例典型的 React Hooks。
以useState
为例, 咱们了解了React Hooks
是如何解决函数组件内没法保留内部数据的问题。
以useEffect
为例, 咱们呢了解了React Hooks
如何处理在数据->视图
之间一些时机
的处理
以及很浅显的提到了Hook
中的数据暂存(快照)的缘由
React Hooks 还有不少种用法, 本章只是梳理 React Hooks 的一些基本概念。
PS: 下一章会着重于《如何在业务中梳理重组封装本身的 Hooks》