使用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 相关文章推荐
选择TreeView控件的树状数据节点的JS方法(jquery)
Feb 06 Javascript
JavaScript实现查找字符串中第一个不重复的字符
Dec 29 Javascript
原生js实现模拟滚动条
Jun 15 Javascript
jQuery与Ajax以及序列化
Feb 01 Javascript
JavaScript弹出对话框的三种方式
Mar 23 Javascript
Angular ui.bootstrap.pagination分页
Jan 20 Javascript
js实现tab切换效果
Feb 16 Javascript
详解react-native-fs插件的使用以及遇到的坑
Sep 12 Javascript
总结js中的一些兼容性易错的问题
Dec 18 Javascript
Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现
Apr 01 Javascript
教你使用vue-cli快速构建的小说阅读器
May 13 Javascript
js 下拉菜单点击旁边收起实现(踩坑记)
Sep 29 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配置文件中最常用四个ini函数
2007/03/19 PHP
建站常用13种PHP开源CMS比较
2009/08/23 PHP
PHP采集腾讯微博的实现代码
2012/01/19 PHP
解析在PHP中使用全局变量的几种方法
2013/06/24 PHP
合并ThinkPHP配置文件以消除代码冗余的实现方法
2014/07/22 PHP
PHP中绘制图像的一些函数总结
2014/11/19 PHP
php实现对两个数组进行减法操作的方法
2015/04/17 PHP
PHP实现支付宝即时到账功能
2016/12/21 PHP
[原创]php使用strpos判断字符串中数字类型子字符串出错的解决方法
2017/04/01 PHP
php生成毫秒时间戳的实例讲解
2017/09/22 PHP
PHP实现微信提现功能(微信商城)
2019/11/21 PHP
070823更新的一个[消息提示框]组件 兼容ie7
2007/08/29 Javascript
javascript之可拖动的iframe效果代码
2008/08/01 Javascript
jQuery操作cookie方法实例教程
2014/11/25 Javascript
JavaScript 计算笛卡尔积实例详解
2016/12/02 Javascript
解决Window10系统下Node安装报错的问题分析
2016/12/13 Javascript
jquery无法为动态生成的元素添加点击事件的解决方法(推荐)
2016/12/26 Javascript
jQuery实现模拟搜索引擎的智能提示功能简单示例
2019/01/27 jQuery
javascript实现的时间格式加8小时功能示例
2019/06/13 Javascript
ng-alain的sf如何自定义部件的流程
2020/06/12 Javascript
如何用JS模拟实现数组的map方法
2020/07/30 Javascript
使用python爬虫实现网络股票信息爬取的demo
2018/01/05 Python
python 从csv读数据到mysql的实例
2018/06/21 Python
python+opencv实现阈值分割
2018/12/26 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
2020/11/30 Python
python 检测图片是否有马赛克
2020/12/01 Python
下面这个程序执行后会有什么错误或者效果
2014/11/03 面试题
幼儿园中班开学寄语
2014/04/03 职场文书
小学教师培训方案
2014/06/09 职场文书
五心教育心得体会
2014/09/04 职场文书
办公室领导干部作风整顿个人整改措施
2014/09/17 职场文书
公司试用期员工自我评价
2014/09/17 职场文书
委托证明范本
2014/11/25 职场文书
家长对孩子的寄语
2015/02/26 职场文书
新学期家长寄语2016
2015/12/03 职场文书
导游词之海南天涯海角
2019/12/05 职场文书