使用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 相关文章推荐
有一段有意思的代码-javascript现实多行信息
Aug 26 Javascript
打豆豆小游戏 用javascript编写的[打豆豆]小游戏
Jan 08 Javascript
Javascript 垃圾收集机制介绍理解
May 14 Javascript
js调用iframe实现打印页面内容的方法
Mar 04 Javascript
jQuery学习笔记之 Ajax操作篇(一) - 数据加载
Jun 23 Javascript
angularJS 中$scope方法使用指南
Feb 09 Javascript
jQuery右下角旋转环状菜单特效代码
Aug 10 Javascript
详解JavaScript对象类型
Jun 16 Javascript
如何提高数据访问速度
Dec 26 Javascript
vue2.X组件学习心得(新手必看篇)
Jul 05 Javascript
详解Vue调用手机相机和相册以及上传
May 05 Javascript
vue和小程序项目中使用iconfont的方法
May 19 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
编写自己的php扩展函数
2006/10/09 PHP
php 文件上传后缀名与文件类型对照表(几乎涵盖所有文件)
2010/05/16 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
2016/09/21 PHP
PHP超低内存遍历目录文件和读取超大文件的方法
2019/05/01 PHP
javascript是怎么继承的介绍
2012/01/05 Javascript
js二级地域选择的实现方法
2013/06/17 Javascript
js局部刷新页面时间具体实现
2013/07/04 Javascript
js 判断图片是否加载完以及实现图片的预下载
2014/08/14 Javascript
JavaScript 学习笔记之操作符(续)
2015/01/14 Javascript
JavaScript实现LI列表数据绑定的方法
2015/08/04 Javascript
js文本框走动跑马灯效果代码分享
2015/08/25 Javascript
jquery常用的12个小功能
2016/07/22 Javascript
通过JS获取Request.QueryString()参数的值实现方法
2016/09/27 Javascript
AngularJS开发教程之控制器之间的通信方法分析
2016/12/25 Javascript
原生js实现水平方向无缝滚动
2017/01/10 Javascript
微信小程序 仿猫眼实现实例代码
2017/03/14 Javascript
JS模拟实现ECMAScript5新增的数组方法
2017/03/20 Javascript
利用Vue.js+Node.js+MongoDB实现一个博客系统(附源码)
2017/04/24 Javascript
vue中的event bus非父子组件通信解析
2017/10/27 Javascript
Vue中的无限加载vue-infinite-loading的方法
2018/04/08 Javascript
Vue.set() this.$set()引发的视图更新思考及注意事项
2018/08/30 Javascript
详解html-webpack-plugin插件(用法总结)
2018/09/12 Javascript
JavaScript 变量,数据类型基础实例详解【变量、字符串、数组、对象等】
2020/01/04 Javascript
vue页面加载时的进度条功能(实例代码)
2020/01/13 Javascript
js操作两个json数组合并、去重,以及删除某一项元素
2020/09/22 Javascript
Python字符串、元组、列表、字典互相转换的方法
2016/01/23 Python
python字符串string的内置方法实例详解
2018/05/14 Python
浅谈python下tiff图像的读取和保存方法
2018/12/04 Python
python中下标和切片的使用方法解析
2019/08/27 Python
解决使用Pandas 读取超过65536行的Excel文件问题
2020/11/10 Python
CSS3 media queries + jQuery实现响应式导航
2016/09/30 HTML / CSS
美国家居装饰和豪华家具购物网站:One Kings Lane
2018/12/24 全球购物
表决心的诗句大全
2014/03/11 职场文书
2016年中学植树节活动总结
2016/03/16 职场文书
机关单位2016年创先争优活动总结
2016/04/05 职场文书
2016年读书月活动总结范文
2016/04/06 职场文书