使用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 相关文章推荐
Ajax,UTF-8还是GB2312 eval 还是execScript
Nov 13 Javascript
使用jQuery fancybox插件打造一个实用的数据传输模态弹出窗体
Jan 15 Javascript
常用js字符串判断方法整理
Oct 18 Javascript
layui中layer前端组件实现图片显示功能的方法分析
Oct 13 Javascript
vue axios请求超时的正确处理方法
Apr 02 Javascript
Vue中props的使用详解
Jun 15 Javascript
使用Vuex解决Vue中的身份验证问题
Sep 28 Javascript
如何优雅的在一台vps(云主机)上面部署vue+mongodb+express项目
Jan 20 Javascript
vuex存值与取值的实例
Nov 06 Javascript
nginx配置域名后的二级目录访问不同项目的配置操作
Nov 06 Javascript
Vue中computed和watch有哪些区别
Dec 19 Vue.js
如何利用JavaScript编写一个格斗小游戏
Jan 06 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常用正则函数实例小结
2016/12/29 PHP
PHP将字符串首字母大小写转换的实例
2017/01/21 PHP
php+redis消息队列实现抢购功能
2018/02/08 PHP
jQuery(1.3.2) 7行代码搞定跟随屏幕滚动的层
2009/05/21 Javascript
JS实现随机数生成算法示例代码
2013/08/08 Javascript
jquery实现的判断倒计时是否结束代码
2016/02/05 Javascript
BootStrap中按钮点击后被禁用按钮的最佳实现方法
2016/09/23 Javascript
微信小程序 页面传参实例详解
2016/11/16 Javascript
基于JS组件实现拖动滑块验证功能(代码分享)
2016/11/18 Javascript
Javascript 闭包详解及实例代码
2016/11/30 Javascript
jQuery表单元素选择器代码实例
2017/02/06 Javascript
javascript 单例模式详解及简单实例
2017/02/14 Javascript
JavaScript基本类型值-Number类型
2017/02/24 Javascript
微信小程序开发之入门实例教程篇
2017/03/07 Javascript
Vue + Webpack + Vue-loader学习教程之功能介绍篇
2017/03/14 Javascript
详解node中创建服务进程
2017/05/09 Javascript
超级简易的JS计算器实例讲解(实现加减乘除)
2017/08/08 Javascript
Python实现的Google IP 可用性检测脚本
2015/04/23 Python
Python使用Dijkstra算法实现求解图中最短路径距离问题详解
2018/05/16 Python
Python实现非正太分布的异常值检测方式
2019/12/09 Python
python matplotlib绘制三维图的示例
2020/09/24 Python
css3给背景图片加颜色遮罩的方法
2019/11/05 HTML / CSS
Chain Reaction Cycles芬兰:世界上最大的在线自行车商店
2017/12/06 全球购物
ONLY瑞典官网:世界知名服装品牌
2018/06/19 全球购物
Gloeilampgoedkoop荷兰:在线购买灯泡
2019/02/16 全球购物
PHP使用Redis队列执行定时任务实例讲解
2021/03/24 PHP
应届毕业生求职信
2013/11/30 职场文书
八年级音乐教学反思
2014/01/09 职场文书
一份婚庆公司创业计划书
2014/01/11 职场文书
大学生创业计划书怎么写
2014/09/15 职场文书
2014财务年度工作总结
2014/11/11 职场文书
2014年绿化工作总结
2014/12/09 职场文书
2016领导干部廉洁从政心得体会
2016/01/19 职场文书
Golang之sync.Pool使用详解
2021/05/06 Golang
判断Python中的Nonetype类型
2021/05/25 Python
前端框架ECharts dataset对数据可视化的高级管理
2022/12/24 Javascript