前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >react 学习(五) 完善 setState 及实现 ref

react 学习(五) 完善 setState 及实现 ref

原创
作者头像
测不准
发布2022-04-12 21:45:42
3960
发布2022-04-12 21:45:42
举报
文章被收录于专栏:与前端沾边与前端沾边

上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二参数作为回调函数。我们先把上一节的工作收个尾再介绍 ref 的实现。

完善 setState

立即执行

我们在代码中实现如下逻辑,传入函数,我们需要修改一下 getState 方法

代码语言:txt
复制
this.setState((state) => ({ number: state.number + 1 }));
this.setState((state) => ({ number: state.number + 1 }));


// src/Component.js
getState() {
  ...
  pendingStates.forEach(nextState => {
    // 对参数进行判断
    if (typeof nextState === 'function') {
      nextState = nextState(state)// 这里把旧的 state 传入,立即执行,这样我们在代码中看到的就类似同步执行,函数返回新的 state 状态
    }
    state = {
      ...state,
      ...nextState
    }
  })
}

相信看完上面代码,大家应该能够理解为什么传入函数就可以同步执行。因为每次都会立即计算获取当前最新的状态。

实现回调函数

setState 的第二个参数会在页面更新后执行,获取到最新的状态返回值。所以我们能想到开始先把回调函数收集,在组件更新完成之后再依次执行,代码如下:

代码语言:txt
复制
// src/Component.js Updater类
初始化需要定义回调函数栈
this.callbacks = []

在 addState 添加状态的同时收集回调函数
addState(partialState, callback) {
  this.pendingStates.push(partialState)
  callback && this.callbacks.push(callback)
  ...
}


在组件完成更新 updateComponent 方法的最后执行回调

updateComponent() {
  const {classInstance, pendingStates, callbacks} = this
  if (pendingStates.length) {
    ...
  }
  // 这里咱们使用个微任务执行,因为 js 的单线程机制,可以保证微任务一定在也买呢渲染后执行
  queueMicrotask(() => {
    callbacks.forEach(cb => cb.call(this))
    this.callbacks.length = [] // 执行完成后清空
  })
}

相信大家看过之前几节的基础上,能够很快的理解上面的代码,如果大家更这实现也基本能实现自己的 react-demo 了。

实现 createRef

我们通常用 ref 来获取真实 dom 节点然后进行操作,上一小节我们知道我们已经把真实的 dom 绑定在了 vdom 上,类组件的实例也能够拿到,所以我们只需加一层判断即可。

首先获取 ref 属性,入口文件中实现如下 dom 结构:

代码语言:txt
复制
// src/index.js

constructor(props) {
  super(props);
  this.a = React.createRef(); // {current: null}
  this.b = React.createRef();
  this.result = React.createRef();
}
  
...
<>
  <input ref={this.a} type="text" /> + <input ref={this.b} type="text" />{" "}
  <button onClick={this.handleClick}>=</button>{" "}
  <input ref={this.result} type="text" />
</>

修改 react.js 文件

代码语言:txt
复制
第一步返回值新增字段
const React = {
  createElement,
  Component,
  createRef,
};
// 一行代码就完事了
function createRef() { return {current: null} }

我们还需要修改下返回的虚拟dom对象,新增 ref 属性

function createElement(type, config, chidlren) {
  let ref 
  if (config) {
    ref = config.ref
    delete config.ref
    ...
  }
  ...
  return {
     ...
     ref
  } 
}

我们注意 ref 对于 dom 来说一般用在类组件和正常的 dom 上,所以我们只需要修改 createDOMmountClassComponent 方法

代码语言:txt
复制
// src/react-dom.js
function createDOM(vdom) {
  // 拿到 ref
  const {type, props, ref} = vdom
  ...
  if (ref) ref.current = dom
  ...
}

function mountClassComponent(vdom) {
  // 同理
  const {type, props, ref} = vdom
  ...
  if (ref) ref.current = classInstance
  ...
}

本小节我们完善了 setState 方法的使用,了解了函数可以同步执行的原因;我们也知道了 ref 的实现原理,只需要对其 current 属性进行绑定即可。下一小节我们学习下 react 的生命周期。如果有不对,欢迎指正!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 完善 setState
    • 立即执行
      • 实现回调函数
      • 实现 createRef
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档