React Hooks 从入门到放弃(一)

本文默认读者对 React Hooks 已经有必定的了解。 所以再也不赘述 Hooks API 的使用了, 还未了解的同窗能够去官网阅读React Hooks API Referencejavascript

React Hooks 基础

使用 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

0. 函数组件

函数组件是用来处理一些简单的 UI 组件, 经过 Props 传入的数据, 抽象封装一些组件。数组

function Header(props) {
    const { title, description, avatar } = props;
    return (
        <div> <img src={avatar} /> <h1>{title}</h1> <p>{description}</p> </div> ); } 复制代码

限制了函数组件使用的缘由一方面在于它没有内部数据, 另外一方面就是没有生命周期, 所以没法实现具备必定交互与逻辑的功能。闭包

1. 使用 React Hooks 时的数据存储

函数组件内定义的变量不是固化的, 执行完成后, 函数内的变量就会被清理掉了(非闭包状况)。因此, 咱们须要经过 Hooks 固化组件须要的一些数据。app

Edit on CodeSandbox

上面是 React Hooks 之 useState 的使用例子, 以下是浅尝辄止的理解:

经过useState, 咱们在某个地方定义了一个对象, 并挂载到某个不会让它消失的地方。useState方法返回的第一个值就是咱们要的数据。useState方法返回的第二个值是一个函数, 能够设置这个对象的值, 而后会触发函数从新渲染。

上面这坨话说的很模糊, 某个地方究竟是哪一个地方, 定义了一个什么样的对象, 又挂载到了什么地方。设置了新值后又是怎么触发渲染的???

若是想从根源上填上这个坑, 大概是须要阅读源码了解 Hooks 的基础实现的 Github 源码连接

在了解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.

2. 使用 React Hooks 处理反作用

反作用(Side Effect), 我的理解, 是在数据->视图的转化过程当中, 出现的一些特别的时机。咱们能够利用这些时机去处理一些业务逻辑。

如下是使用useEffect的一个简单的计数 Demo.

Edit on CodeSandbox

使用useEffect去实如今渲染完成以后要去处理的一些事情。 你们也能够在官网的 API Reference 中找到 React useEffect 说明。

咱们能够经过流程图加深理解useEffect这个 Hook。

以上是useEffectHook 的大体执行逻辑, 经过此图会发现useEffect多了一步数据比对的过程, 只有当如下条件成立时, SideEffect 才会触发调用。

  1. useEffect 第一次执行之时
  2. useEffect 的依赖存在变动之时

咱们修改上面计数的例子就能够更好的理解两个 Hook。

Edit on CodeSandbox

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

  1. step更新时, useEffectcount没有变化, 因此没有触发更新
  2. useEffect触发时, 使用的是 Hook 中暂存的数据, 因此步长step仍然是 1.

咱们在 Hook 加载流程上补充上对比的过程。

Hook中存入的是上一次渲染后的快照值, 因此在执行时, 也会使用上一次渲染留下来的值。

到这里, 咱们归纳下函数组件的渲染流程

3. 总结

本文只是提到了useState, useEffect这两例典型的 React Hooks。

useState为例, 咱们了解了React Hooks是如何解决函数组件内没法保留内部数据的问题。

useEffect为例, 咱们呢了解了React Hooks如何处理在数据->视图之间一些时机的处理

以及很浅显的提到了Hook中的数据暂存(快照)的缘由

React Hooks 还有不少种用法, 本章只是梳理 React Hooks 的一些基本概念。

PS: 下一章会着重于《如何在业务中梳理重组封装本身的 Hooks》

4. 参考 Reference

React Hook 解析 - 风吹老了好少年的文章 - 知乎

相关文章
相关标签/搜索