使用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 相关文章推荐
javascript处理table表格的代码
Dec 06 Javascript
jquery ajax 同步异步的执行 return值不能取得的解决方案
Jan 08 Javascript
Extjs中RowExpander控件的默认展开问题示例探讨
Jan 24 Javascript
jQuery实现动态添加和删除一个div
Aug 12 Javascript
JavaScript的设计模式经典之代理模式
Feb 24 Javascript
微信小程序 wxapp内容组件 text详细介绍
Oct 31 Javascript
基于 Vue 实现一个酷炫的 menu插件
Nov 14 Javascript
微信小程序scroll-view实现字幕滚动
Jul 14 Javascript
Vue 实时监听窗口变化 windowresize的两种方法
Nov 06 Javascript
JS实现的新闻列表自动滚动效果示例
Jan 30 Javascript
vue微信分享的实现(在当前页面分享其他页面)
Apr 16 Javascript
vue@cli3项目模板怎么使用public目录下的静态文件
Jul 07 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/02/14 PHP
php gd2 上传图片/文字水印/图片水印/等比例缩略图/实现代码
2010/05/15 PHP
PHP 5.3.1 安装包 VC9 VC6不同版本的区别是什么
2010/07/04 PHP
php使用mysqli向数据库添加数据的方法
2015/03/20 PHP
用PHP代码给图片加水印
2015/07/01 PHP
php轻松实现文件上传功能
2016/03/03 PHP
Zend Framework开发入门经典教程
2016/03/23 PHP
CI框架支持$_GET的两种实现方法
2016/05/18 PHP
php实现微信公众号创建自定义菜单功能的实例代码
2019/06/11 PHP
jQuery对象和Javascript对象之间转换的实例代码
2013/03/20 Javascript
阻止子元素继承父元素事件具体思路及实现
2013/05/02 Javascript
JS中window.open全屏命令解析及使用示例
2013/12/11 Javascript
JQuery对表单元素的基本操作使用总结
2014/07/18 Javascript
js实现复选框的全选和取消全选效果
2017/01/03 Javascript
angular.js+node.js实现下载图片处理详解
2017/03/31 Javascript
jQuery序列化后的表单值转换成Json
2017/06/16 jQuery
vue基础之事件v-onclick=&quot;函数&quot;用法示例
2019/03/11 Javascript
详解jQuery设置内容和属性
2019/04/11 jQuery
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
浅谈Node新版本13.2.0正式支持ES Modules特性
2019/11/25 Javascript
d3.js实现图形拖拽
2019/12/19 Javascript
解决ant Design Search无法输入内容的问题
2020/10/29 Javascript
[01:00:25]2018DOTA2亚洲邀请赛3月30日 小组赛A组 VG VS Liquid
2018/03/31 DOTA
python2.7删除文件夹和删除文件代码实例
2013/12/18 Python
Python代码实现KNN算法
2017/12/20 Python
深入浅析Python中的迭代器
2019/06/04 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
2019/07/22 Python
Python环境Pillow( PIL )图像处理工具使用解析
2019/09/12 Python
python代码实现将列表中重复元素之间的内容全部滤除
2020/05/22 Python
五分钟学会HTML5的WebSocket协议
2019/11/22 HTML / CSS
西班牙高科技产品购物网站:MejorDeseo
2019/09/08 全球购物
Hobbs官方网站:英国奢华女性时尚服装
2020/02/22 全球购物
2015年行政助理工作总结
2015/04/30 职场文书
2015年大学班主任工作总结
2015/04/30 职场文书
2015年新教师个人工作总结
2015/10/14 职场文书
python爬虫--selenium模块
2021/03/31 Python