实现 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。

  1. let state;
  2. function useState(init) {
  3. function setState(newState) {
  4. if (typeof newState === "function") {
  5. // 支持旧值传入更新
  6. state = newState(state);
  7. } else {
  8. state = newState;
  9. }
  10. // setState 后调用组件 render
  11. // render();
  12. }
  13. if (!state) {
  14. state = init;
  15. }
  16. return [state, setState];
  17. }

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

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

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

  1. let _deps;
  2. function useEffect(callback, deps) {
  3. if (
  4. deps === undefined || // 就是不传 deps,就是每次都执行副作用
  5. (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用
  6. !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行
  7. ) {
  8. // 如果有 cleanUp 就执行清理
  9. if (typeof _deps._cleanUp === "function") {
  10. _deps._cleanUp();
  11. }
  12. _deps._cleanUp = callback();
  13. }
  14. }

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

  1. let _arr = [];
  2. let cursor = 0;
  3. function useState(init) {
  4. const current = cursor;
  5. function setState(newState) {
  6. if (typeof newState === "function") {
  7. // 支持旧值传入更新
  8. _arr[current] = newState(_arr[current]);
  9. } else {
  10. _arr[current] = newState;
  11. }
  12. // setState 后调用组件 render
  13. render();
  14. }
  15. if (!_arr[current]) {
  16. _arr[current] = init;
  17. }
  18. cursor++;
  19. return [_arr[current], setState];
  20. }
  21. function useEffect(callback, deps) {
  22. const effect = _arr[cursor] || {};
  23. const { _deps, _cleanUp } = effect;
  24. if (
  25. deps === undefined || // 就是不传 deps,就是每次都执行副作用
  26. (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用
  27. !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行
  28. ) {
  29. // 如果有 cleanUp 就执行清理
  30. if (typeof _cleanUp === "function") {
  31. _cleanUp();
  32. }
  33. effect._cleanUp = callback();
  34. effect._deps = deps;
  35. _arr[cursor] = effect;
  36. }
  37. cursor++;
  38. }

全部代码在 CodeSandBox

完。

实现 React Hooks的更多相关文章

  1. 通过 React Hooks 声明式地使用 setInterval

    本文由云+社区发表 作者:Dan Abramov 接触 React Hooks 一定时间的你,也许会碰到一个神奇的问题: setInterval 用起来没你想的简单. Ryan Florence 在他 ...

  2. 初探React Hooks & SSR改造

    Hooks React v16.8 发布了 Hooks,其主要是解决跨组件.组件复用的状态管理问题. 在 class 中组件的状态封装在对象中,然后通过单向数据流来组织组件间的状态交互.这种模式下,跨 ...

  3. React hooks实践

    前言 最近要对旧的项目进行重构,统一使用全新的react技术栈.同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function c ...

  4. 理解 React Hooks

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由志航发表于云+社区专栏 TL;DR 一句话总结 React Hooks 就是在 react 函数组件中,也可以使用类组件(classe ...

  5. React Hooks新特性学习随笔

    React Hooks 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 前言 本篇主要以讲几个常用的api为主. 1.u ...

  6. 关于React Hooks,你不得不知的事

    React Hooks是React 16.8发布以来最吸引人的特性之一.在开始介绍React Hooks之前,让咱们先来理解一下什么是hooks.wikipedia是这样给hook下定义的: In c ...

  7. react hooks 全面转换攻略(三) 全局存储解决方案

    针对 react hooks 的新版本解决方案 一.redux维持原方案 若想要无缝使用原来的 redux,和其配套的中间件 promise,thunk,saga 等等的话 可以使用 redux-re ...

  8. react新特性 react hooks

    本文介绍的是react新特性react hooks,本文面向的是有一定react开发经验的小伙伴,如果你对react还不是很熟悉的话我建议你先学习react并多多联系. 首先我们都知道react有3种 ...

  9. 30分钟精通React今年最劲爆的新特性——React Hooks

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周 ...

  10. React Hooks 深入系列 —— 设计模式

    本文是 React Hooks 深入系列的后续.此篇详细介绍了 Hooks 相对 class 的优势所在, 并介绍了相关 api 的设计思想, 同时对 Hooks 如何对齐 class 的生命周期钩子 ...

随机推荐

  1. Fiddler工具学习使用总结

    1.初识fiddler: 作用:截获http/HTTPS请求,查看截获的请求内容,伪造客户端请求和服务器响应,测试网站性能,解密https的web会话,提供插件. 工作环境:支持素有操作系统和所有浏览 ...

  2. 4.keras-交叉熵的介绍和应用

    keras-交叉熵的介绍和应用 1.载入数据以及预处理 import numpy as np from keras.datasets import mnist from keras.utils imp ...

  3. web静态页面资源访问路径问题

    我使用的是idea,今天搭建一个项目时遇见了css和js路径错误,导致浏览器获取不到资源路径 这是我最开始写的路径 <link href="/main/loginMain.css&qu ...

  4. Backup Database pubs to Disk='D:\DataSQL\pubs.bak' --->动态备份所有数据库

    备份数据库 在项目实施时,备份恢复数据库还是有必要的,自动或傻瓜式的操作比较方便,未测试,失业了,现在静不下心来,有机会要求再做这类操作时实现它,此处先收藏备用 /* <Dynamic SQL ...

  5. Excel随机生成批量日期,以及注意事项

    这个是WPS里写的一个函数,用来随机生成日期.首先E1和E2是两个日期端点,右键把单元格格式先设置成“日期”中的“xxxx年xx月xx日 xx:xx”,然后E3=E1-E2算出它们的距离. 在E4里面 ...

  6. 解决Mac上打开txt文件乱码问题

    出处:https://www.jianshu.com/p/f55ddf1e9839 经常会在Mac上打开一个txt文件,发现里面的中文都是乱码,问题是在Windows和手机上看都完全是正常的,这就十分 ...

  7. 【JMeter_17】JMeter逻辑控制器__随机顺序控制器<Random Order Controller>

    随机顺序控制器<Random Order Controller> 业务逻辑: 当控制器被触发时,将控制器下的所有子节点顺序打乱执行一遍,执行一遍,执行一遍,不是执行一个. 注意:是将子节点 ...

  8. cc21a -c++重载成员操作符*,->,代码示范

    cc21a重载成员操作符*,->, *,解引用操作符 ->箭头操作符,用于智能指针类 #include "pointer.h" //pointer.cpp #inclu ...

  9. 用VC++6.0,双击主对话框中的按钮时,不能跳转到代码处

    1. 首先在项目中--[生成]build--[清除解决方案]clean 2. 关闭项目 3. 删除项目中的[Debug]下所有文件 4. 把*.aps,*.clw,*.ncb,*.opt删掉----- ...

  10. 13.实战交付一套dubbo微服务到k8s集群(6)之交付dubbo服务的消费者集群到K8S

    构建dubbo-demo-consumer,可以使用和dubbo-demo-service的流水线来构建 1.登录jenkins构建dubbo-demo-consumer  2.填写构建dubbo-d ...