实现 React Hooks

UI 开发有两个问题:

  1. 展示复用

  2. 逻辑复用

展示复用目前基本使用组件化来解决,逻辑复用一直以来都没有特别好的解决方案。React 从一开始的 mixin ,到 高阶组件 以及 Render Props ,都是在试图解决这个问题,但是都引入了一些别的问题。

Mixins

  1. 命名空间冲突

  2. 数据来源不清晰

Higher-order Components

  1. props 属性来源不清晰

  2. props 上命名冲突

  3. 额外的组件渲染带来性能问题

Render Props(Vue 中的 Renderless Components)

  1. 解决了 命名空间冲突、数据来源不清晰的问题,仍然会带来额外组件实例的性能消耗

Hooks

在前段时间 Hooks 发布后,我认为 React 找到了【有状态】组件【函数式】【复用逻辑】的解决方案。
先说有状态:一般来说,无状态组件直接使用函数组件就行,省去了实例化的样板代码和性能消耗。不涉及到 state 的存取,可以直接写个 helper 函数处理一下,方便又快捷。
再说函数式:class 组件是面向对象的,每一次声明、声明周期都逃不开 this,而 hooks 更加函数式,调用一个函数,传入的是初始值,返回修改值,没有副作用。
最后说复用逻辑:DRY,一般来说,相同的代码不写第二次,在 class 组件中,通过生命周期方法对 state 修改,然后 rerender,在使用了 hooks 以后,我们可以通过 hooks 触发 render,render 调用 hooks 时,根据传入值的比较,来决定是否触发 render,然后把 hooks 返回的值填充到页面上。

实现

hooks 给人最直接的印象就是可以在 function 组件中使用 state 了。但它也有着不同于 class 组件的心智模型,从生命周期的思维跳到 update circle,刚开始 useEffect 总会写一些无限循环。接下来我们先来写一个简易版的 useState,来模仿 React。

let state;
function useState(init) {
  function setState(newState) {
    if (typeof newState === "function") {
      // 支持旧值传入更新
      state = newState(state);
    } else {
      state = newState;
    }
    // setState 后调用组件 render
    // render();
  }
  if (!state) {
    state = init;
  }
  return [state, setState];
}

上面就是一个 useState 了,接下来继续写 useEffect.

let _deps;
function useEffect(callback, deps) {
  if (
    deps === undefined || // 就是不传 deps,就是每次都执行副作用
    (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用
    !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行
  ) {
    callback();
  }
}

这就是 useEffect 基本实现了,当然还有一个问题,callback 的 return 函数问题。

let _deps;
function useEffect(callback, deps) {
  if (
    deps === undefined || // 就是不传 deps,就是每次都执行副作用
    (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用
    !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行
  ) {
    // 如果有 cleanUp 就执行清理
    if (typeof _deps._cleanUp === "function") {
      _deps._cleanUp();
    }
    _deps._cleanUp = callback();
  }
}

接下来,还有个重要问题,hooks 的顺序问题,其实就是把 state 和 deps 存到数组里。

let _arr = [];
let cursor = 0;
function useState(init) {
  const current = cursor;
  function setState(newState) {
    if (typeof newState === "function") {
      // 支持旧值传入更新
      _arr[current] = newState(_arr[current]);
    } else {
      _arr[current] = newState;
    }
    // setState 后调用组件 render
    render();
  }
  if (!_arr[current]) {
    _arr[current] = init;
  }
  cursor++;
  return [_arr[current], setState];
}
function useEffect(callback, deps) {
  const effect = _arr[cursor] || {};
  const { _deps, _cleanUp } = effect;
  if (
    deps === undefined || // 就是不传 deps,就是每次都执行副作用
    (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用
    !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行
  ) {
    // 如果有 cleanUp 就执行清理
    if (typeof _cleanUp === "function") {
      _cleanUp();
    }
    effect._cleanUp = callback();
    effect._deps = deps;
    _arr[cursor] = effect;
  }
  cursor++;
(0)

相关推荐

  • React Hooks

    Hooks介绍 之前没有用hooks写react的时候,用class类组件,state在构造函数定义,然后是钩子函数. 在这里,发现用的是函数组件,useState来定义state,useEffect ...

  • 如何利用 React Hooks 管理全局状态

    如何利用 React Hooks 管理全局状态 本文写于 2020 年 1 月 6 日 React 社区最火的全局状态管理库必定是 Redux,但是 Redux 本身就是为了大型管理数据而妥协设计的- ...

  • 蒲公英 · JELLY技术周刊 Vol.17: 90 行代码实现 React Hooks

    蒲公英 · JELLY技术周刊 Vol.17 React Hooks 相信大家都不陌生,自被设计出以来就备受好评,在很多场景中都有极高的使用率,其中原理更是很多大厂面试中的必考题,很多朋友都能够如数家 ...

  • react hooks系列之useRef

    react hooks是 react 16.8 引入的特性,这里我们通过对react-hook-form进行分析来了解成熟的库是如何使用hook的.这将是一个系列,首先推荐 useRef 简介 在re ...

  • React实战教程之从零开始手把手教你使用 React 最新特性Hooks API 打造一款计算机知识测验App

    前言 React 框架的优雅不言而喻,组件化的编程思想使得React框架开发的项目代码简洁,易懂,但早期 React 类组件的写法略显繁琐.React Hooks 是 React 16.8 发布以来最 ...

  • Typescript结合React实践

    原创 慕晨同学 前端技术优选 今天 作者:慕晨同学 原文地址:https://juejin.im/post/5d37b5d9f265da1bd605e5e1 写在前面 Typescript是JavaS ...

  • 前端框架之争丨除了Vue、Angular和React还有谁与之争锋

    作者:葡萄城控件技术团队 来源:葡萄城官网 当今涌出的大量框架让人眼花缭乱不知如何选择,今天将比较五个最流行的前端JavaScript框架,并作出概述,介绍其主要功能.工具.学习曲线及其他因素,帮助您 ...

  • React 328道最全面试题(持续更新)

    今天的React题没有太多的故事-- 半个月前出了248个Vue的知识点,受到很多朋友的关注,都强烈要求再出多些React相前的面试题,受到大家的邀请,我又找了20多个React的使用者,他们给出了3 ...

  • Electron+React 快速搭建一个桌面应用

    一.项目技术栈:Electron+react+react-router+antd1.Electron:electron是一个使用js,html和css等的web技术创建原生桌面应用的框架,他基于chr ...