使用store来优化React组件的方法


Posted in Javascript onOctober 23, 2017

在使用 React 编写组件的时候,我们常常会碰到两个不同的组件之间需要共享状态情况,而通常的做法就是提升状态到父组件。但是这样做会有一个问题,就是尽管只有两个组件需要这个状态,但是因为把状态提到了父组件,那么在状态变化的时候,父组件以及其下面的所有子组件都会重新 render,如果你的父组件比较复杂,包含了其他很多子组件的话,就有可能引起性能问题。

Redux 通过把状态放在全局的 store 里,然后组件去订阅各自需要的状态,当状态发生变化的时候,只有那些订阅的状态发生变化的组件才重新 render,这样就避免了上面说的提升状态所带来的副作用。但是,当我们在写一个 React 组件库的时候,redux 加 react-redux 的组合可能就有点太重了。所以我们可以自己写一个简单的 store,来实现类似 Redux 的订阅模式。

参考 Redux 的实现来写一个简版的 createStore:

function createStore(initialState) {
 let state = initialState;
 const listeners = [];

 function setState(partial) {
  state = {
   ...state,
   ...partial,
  };
  for (let i = 0; i < listeners.length; i++) {
   listeners[i]();
  }
 }

 function getState() {
  return state;
 }

 function subscribe(listener) {
  listeners.push(listener);

  return function unsubscribe() {
   const index = listeners.indexOf(listener);
   listeners.splice(index, 1);
  };
 }

 return {
  setState,
  getState,
  subscribe,
 };
}

我们的 createStore 非常简单,算上空行也只有 33 行,总共暴露了 3 个方法,没有 Redux 里的 dispatch 和 reducer,直接通过 setState 方法改变状态。下面我们来用它一个计数器的例子。

class Counter extends React.Component {
 constructor(props) {
  super(props);

  // 初始化 store
  this.store = createStore({
   count: 0,
  });
 }

 render() {
  return (
   <div>
    <Buttons store={store} />
    <Result store={store} />
   </div>
  )
 }
}

class Buttons extends React.Component {
 handleClick = (step) => () => {
  const { store } = this.props;
  const { count } = store.getState();
  store.setState({ count: count + step });
 }

 render() {
  return (
   <div>
    <button onClick={this.handleClick(1)}>+</button>
    <button onClick={this.handleClick(1)}>-</button>
   </div>
  );
 }
}

class Result extends React.Component {
 constructor(props) {
  super(props);

  this.state = {
   count: props.store.getState().count,
  };
 }

 componentDidMount() {
  this.props.store.subscribe(() => {
   const { count } = this.props.store.getState();
   if (count !== this.state.count) {
    this.setState({ count });
   }
  });
 }

 render() {
  return (
   <div>{this.state.count}</div>
  );
 };
}

例子中 Buttons 里通过 store.setState 来改变 store 中的状态,并不会引起整个 Counter 的重新 render,但是因为 Result 中订阅了 store 的变化,所以当 count 有变化的时候就可以通过改变自己组件内的状态来重新 render,这样就巧妙地避免了不必须要的 render。

最后,上面的 createStore 虽然只有几十行代码,我还是把它写成了一个叫 mini-store 库放在 GitHub 上,并且提供了类似 Redux 的 Provider 和 connect 方法,总共加起来也就 100 多行代码。如果你也在写 React 组件库,需要管理一个复杂组件的状态,不妨试试这个优化方式。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Z-Blog中用到的js代码
Mar 15 Javascript
javascript 节点遍历函数
Mar 28 Javascript
JS实现5秒钟自动封锁div层的方法
Feb 20 Javascript
解决js图片加载时出现404的问题
Nov 30 Javascript
jQuery中text() val()和html()的区别实例详解
Jun 28 Javascript
jquery获取input type=text中的值的各种方式(总结)
Dec 02 Javascript
通过jsonp获取json数据实现AJAX跨域请求
Jan 22 Javascript
关于使用js算总价的问题
Jun 23 Javascript
JS库particles.js创建超炫背景粒子插件(附源码下载)
Sep 13 Javascript
微信小程序实现的一键拨号功能示例
Apr 24 Javascript
如何在Angular8.0下使用ngx-translate进行国际化配置
Jul 24 Javascript
解决vue axios跨域 Request Method: OPTIONS问题(预检请求)
Aug 14 Javascript
node文件批量重命名的方法示例
Oct 23 #Javascript
详解vue 实例方法和数据
Oct 23 #Javascript
深入浅析javascript继承体系
Oct 23 #Javascript
Vue.js组件通信的几种姿势
Oct 23 #Javascript
Vue2.0+ElementUI实现表格翻页的实例
Oct 23 #Javascript
JavaScript之创意时钟项目(实例讲解)
Oct 23 #Javascript
浅谈js的解析顺序 作用域 严格模式
Oct 23 #Javascript
You might like
239军机修复记
2021/03/02 无线电
用PHPdig打造属于你自己的Google[图文教程]
2007/02/14 PHP
PHP生成树的方法
2015/07/28 PHP
php的mail函数发送UTF-8编码中文邮件时标题乱码的解决办法
2015/10/20 PHP
老生常谈ThinkPHP中的行为扩展和插件(推荐)
2017/05/05 PHP
Laravel模糊查询区分大小写的实例
2019/09/29 PHP
date.parse在IE和FF中的区别
2010/07/29 Javascript
Javascript在IE下设置innerHTML时出现未知的运行时错误的解决方法
2011/01/12 Javascript
基于jQuery的星级评分插件
2011/08/12 Javascript
基于jquery的网站幻灯片切换效果焦点图代码
2013/09/15 Javascript
nodejs教程之制作一个简单的文章发布系统
2014/11/21 NodeJs
简介JavaScript中Math.cos()余弦方法的使用
2015/06/15 Javascript
JavaScript基础篇(6)之函数表达式闭包
2015/12/11 Javascript
vuejs在解析时出现闪烁的原因及防止闪烁的方法
2016/09/19 Javascript
layer弹出层中H5播放器全屏出错的解决方法
2017/02/21 Javascript
原生JS写Ajax的请求函数功能
2017/12/22 Javascript
在vue中实现点击选择框阻止弹出层消失的方法
2018/09/15 Javascript
5分钟教你用nodeJS手写一个mock数据服务器的方法
2019/09/10 NodeJs
Angular5整合富文本编辑器TinyMCE的方法(汉化+上传)
2020/05/26 Javascript
如何利用javascript接收json信息并进行处理
2020/08/06 Javascript
[01:12:40]DOTA2-DPC中国联赛 正赛 DLG vs XG BO3 第三场 1月25日
2021/03/11 DOTA
python登录QQ邮箱发信的实现代码
2013/02/10 Python
python中快速进行多个字符替换的方法小结
2016/12/15 Python
python画出三角形外接圆和内切圆的方法
2018/01/25 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
15行Python代码实现网易云热门歌单实例教程
2019/03/10 Python
为什么从Python 3.6开始字典有序并效率更高
2019/07/15 Python
python面向对象 反射原理解析
2019/08/12 Python
Python中six模块基础用法
2019/12/08 Python
Pythonic版二分查找实现过程原理解析
2020/08/11 Python
建材业务员岗位职责
2013/12/08 职场文书
幼儿园六一儿童节文艺汇演主持词
2014/03/21 职场文书
网络工程师自荐书范文
2014/04/01 职场文书
升职自我推荐信范文
2015/03/25 职场文书
产品调价通知函
2015/04/20 职场文书
vue响应式原理与双向数据的深入解析
2021/06/04 Vue.js