使用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 相关文章推荐
js 模拟气泡屏保效果代码
Jul 10 Javascript
javascript 全选与全取消功能的实现代码
Dec 23 Javascript
基于javascript实现按圆形排列DIV元素(二)
Dec 02 Javascript
JS实现图片预加载之无序预加载功能代码
May 12 Javascript
Vuex实现计数器以及列表展示效果
Mar 10 Javascript
详解如何用babel转换es6的class语法
Apr 03 Javascript
Vue实现开心消消乐游戏算法
Oct 22 Javascript
如何通过javaScript去除字符串两端的空白字符
Feb 06 Javascript
vue实现一个6个输入框的验证码输入组件功能的实例代码
Jun 29 Javascript
JavaScript如何实现监听键盘输入和鼠标监点击
Jul 20 Javascript
Vue axios获取token临时令牌封装案例
Sep 11 Javascript
vue3引入highlight.js进行代码高亮的方法实例
Apr 08 Vue.js
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开发GUI
2006/10/09 PHP
PHP使用星号隐藏用户名,手机和邮箱的实现方法
2016/09/22 PHP
PHP 面向对象程序设计之类属性与类常量实现方法分析
2020/04/13 PHP
基于jquery的滚动条滚动固定div(附演示下载)
2012/10/29 Javascript
JavaScript的模块化:封装(闭包),继承(原型) 介绍
2013/07/22 Javascript
js仿百度贴吧验证码特效实例代码
2014/01/16 Javascript
JS创建类和对象的两种不同方式
2014/08/08 Javascript
javascript动态修改Li节点值的方法
2015/01/20 Javascript
javascript正则表达式基础知识入门
2015/04/20 Javascript
js表格排序实例分析(支持int,float,date,string四种数据类型)
2015/05/06 Javascript
javascript排序函数实现数字排序
2015/06/26 Javascript
信息页文内画中画广告js实现代码(文中加载广告方式)
2016/01/03 Javascript
jQuery图片渐变特效的简单实现
2016/06/25 Javascript
微信小程序实战之轮播图(3)
2017/04/17 Javascript
vue 之 .sync 修饰符示例详解
2018/04/21 Javascript
对Vue table 动态表格td可编辑的方法详解
2018/08/28 Javascript
vue 的 solt 子组件过滤过程解析
2019/09/07 Javascript
京东优选小程序的实现代码示例
2020/02/25 Javascript
[03:56]显微镜下的DOTA2第十一期——鬼畜的死亡先知播音员
2014/06/23 DOTA
使用Python编写类UNIX系统的命令行工具的教程
2015/04/15 Python
Python字符串格式化
2015/06/15 Python
Python编程实现正则删除命令功能
2017/08/30 Python
python 中pyqt5 树节点点击实现多窗口切换问题
2019/07/04 Python
django框架用户权限中的session缓存到redis中的方法
2019/08/06 Python
Python实现生成密码字典的方法示例
2019/09/02 Python
tensorflow -gpu安装方法(不用自己装cuda,cdnn)
2020/01/20 Python
python实现图像拼接
2020/03/05 Python
Python 实现自动完成A4标签排版打印功能
2020/04/09 Python
美国高街时尚品牌:OASAP
2016/07/24 全球购物
什么是Web Service?
2012/07/25 面试题
学习新党章思想汇报
2014/01/09 职场文书
办护照工作证明范本
2014/01/14 职场文书
竞选劳动委员演讲稿
2014/04/28 职场文书
倡议书作文
2015/01/19 职场文书
Python实现简单的猜单词
2021/06/15 Python
python实现简单的聊天小程序
2021/07/07 Python