使用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 相关文章推荐
Ext 今日学习总结
Sep 19 Javascript
人人网javascript面试题 可以提前实现下
Jan 05 Javascript
Jqgrid设置全选(选择)及获取选择行的值示例代码
Dec 28 Javascript
用js替换除数字与逗号以外的所有字符的代码
Jun 07 Javascript
在Google 地图上实现做的标记相连接
Jan 05 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(二)
Dec 10 Javascript
两种方法解决javascript url post 特殊字符转义 + &amp; #
Apr 13 Javascript
JS实现漂亮的时间选择框效果
Aug 20 Javascript
javascript中对象的定义、使用以及对象和原型链操作小结
Dec 14 Javascript
EasyUI折叠表格层次显示detailview详解及实例
Dec 28 Javascript
BootStrap daterangepicker 双日历控件
Jun 02 Javascript
Javascript中的奇葩知识,你知道吗?
Jan 25 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实现采集程序原理和简单示例代码
2007/03/18 PHP
php文件怎么打开 如何执行php文件
2011/12/21 PHP
php简单定时执行任务的实现方法
2015/02/23 PHP
PHP简单实现冒泡排序的方法
2016/12/26 PHP
PHP封装的mysqli数据库操作类示例
2019/02/16 PHP
浅析PHP中的 inet_pton 网络函数
2019/12/16 PHP
jQuery弹出(alert)select选择的值
2013/04/21 Javascript
jQuery的each终止或跳过示例代码
2013/12/12 Javascript
JQuery中绑定事件(bind())和移除事件(unbind())
2015/02/27 Javascript
JavaScript用构造函数如何获取变量的类型名
2016/12/23 Javascript
vue页面使用阿里oss上传功能的实例(二)
2017/08/09 Javascript
Redux 和 Mobx的选择问题:让你不再困惑!
2017/09/18 Javascript
vue 本地环境跨域请求proxyTable的方法
2018/09/19 Javascript
Vue CLI 3.x 自动部署项目至服务器的方法
2019/04/02 Javascript
微信小程序封装分享与分销功能过程解析
2019/08/13 Javascript
js实现简单的倒计时
2021/01/28 Javascript
Python scikit-learn 做线性回归的示例代码
2017/11/01 Python
python中的插值 scipy-interp的实现代码
2018/07/23 Python
基于tensorflow加载部分层的方法
2018/07/26 Python
python实现本地图片转存并重命名的示例代码
2018/10/27 Python
Windows下Python3.6安装第三方模块的方法
2018/11/22 Python
Django 删除upload_to文件的步骤
2020/03/30 Python
Python通过递归函数输出嵌套列表元素
2020/10/15 Python
香港No.1得奖零食网:香港零食大王
2016/07/22 全球购物
几个常见的软件测试问题
2016/09/07 面试题
中专毕业生个人职业生涯规划
2014/02/19 职场文书
哈弗商学院毕业生求职信
2014/02/26 职场文书
销售主管竞聘书
2014/03/31 职场文书
医学专业自荐信
2014/06/14 职场文书
大学生学雷锋活动总结
2014/06/26 职场文书
党员检讨书
2014/10/13 职场文书
2014年学生会部门工作总结
2014/11/07 职场文书
优秀党员申报材料
2014/12/18 职场文书
设备技术员岗位职责
2015/04/11 职场文书
七一表彰大会简报
2015/07/20 职场文书
bootstrapv4轮播图去除两侧阴影及线框的方法
2022/02/15 HTML / CSS