使用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 相关文章推荐
JQuery 学习笔记 选择器之一
Jul 23 Javascript
学习ExtJS fit布局使用说明
Oct 08 Javascript
页面版文本框智能提示JS代码
Nov 20 Javascript
JQuery从头学起第一讲
Jul 04 Javascript
jquery 图片上传按比例预览插件集合
May 28 Javascript
js 代码优化点滴记录
Feb 19 Javascript
JS实现Enter键跳转及控件获得焦点
Aug 12 Javascript
js对字符的验证方法汇总
Feb 04 Javascript
JavaScript中的this机制
Jan 30 Javascript
Javascript6中字符串的四个新用法分享
Sep 11 Javascript
node.js中事件触发器events的使用方法实例分析
Nov 23 Javascript
jQuery 实现DOM元素拖拽交换位置的实例代码
Jul 14 jQuery
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中substr()与explode()函数用法分析
2014/11/24 PHP
将PHP从5.3.28升级到5.3.29时Nginx出现502错误
2015/05/09 PHP
php生成gif动画的方法
2015/11/05 PHP
php设计模式之观察者模式定义与用法经典示例
2019/09/19 PHP
用JavaScript编写COM组件的步骤
2009/03/17 Javascript
理解 JavaScript 预解析
2009/10/25 Javascript
用原生JavaScript实现jQuery的$.getJSON的解决方法
2013/05/03 Javascript
JS检测图片大小的实例
2013/08/21 Javascript
方便实用的jQuery checkbox复选框全选功能简单实例
2013/10/09 Javascript
超级简单的jquery操作表格方法
2014/12/15 Javascript
javascript实现树形菜单的方法
2015/07/17 Javascript
详解Node.js包的工程目录与NPM包管理器的使用
2016/02/16 Javascript
怎么限制input的text里输入的值只能是数字(正则、js)
2016/05/16 Javascript
JavaScript对象封装的简单实现方法(3种方法)
2017/01/03 Javascript
es6函数name属性功能与用法实例分析
2020/04/18 Javascript
原生js实现购物车
2020/09/23 Javascript
解决Antd Table表头加Icon和气泡提示的坑
2020/11/17 Javascript
[00:17]天涯墨客一技能展示
2018/08/25 DOTA
Python中内置数据类型list,tuple,dict,set的区别和用法
2015/12/14 Python
详细介绍Python的鸭子类型
2016/09/12 Python
Python基于xlrd模块操作Excel的方法示例
2018/06/21 Python
flask中的wtforms使用方法
2018/07/21 Python
pyqt5的QWebEngineView 使用模板的方法
2018/08/18 Python
python,Django实现的淘宝客登录功能示例
2019/06/12 Python
Tensorflow实现神经网络拟合线性回归
2019/07/19 Python
CSS3 @media的基本用法总结
2019/09/10 HTML / CSS
美国智能家居专家:tink
2019/06/04 全球购物
简述进程的启动、终止的方式以及如何进行进程的查看
2013/07/12 面试题
J2EE的优越性主要表现在哪些方面
2016/03/28 面试题
应届毕业生个人求职自荐信
2014/01/06 职场文书
预备党员2014全国两会学习心得体会
2014/03/10 职场文书
农行心得体会
2014/09/02 职场文书
普通党员群众路线教育实践活动心得体会
2014/11/04 职场文书
教育实习指导教师评语
2014/12/31 职场文书
夫妻吵架保证书
2015/05/08 职场文书
毕业设计答辩开场白
2015/05/29 职场文书