使用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 相关文章推荐
做网页的一些技巧(续)
Feb 01 Javascript
jquery插件制作教程 txtHover
Aug 17 Javascript
HTML页面弹出居中可拖拽的自定义窗口层
May 07 Javascript
jQuery trigger()方法用法介绍
Jan 13 Javascript
JS简单实现获取元素的封装操作示例
Apr 07 Javascript
微信小程序图片横向左右滑动案例
May 19 Javascript
基于js中的原型(全面讲解)
Sep 19 Javascript
轻松理解vue的双向数据绑定问题
Oct 30 Javascript
利用JQUERY实现多个AJAX请求等待的实例
Dec 14 jQuery
Node使用Sequlize连接Mysql报错:Access denied for user ‘xxx’@‘localhost’
Jan 03 Javascript
对TypeScript库进行单元测试的方法
Jul 18 Javascript
openlayers 3实现车辆轨迹回放
Sep 24 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
一个基于PDO的数据库操作类
2011/03/24 PHP
Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
2013/06/14 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
JavaScript高级程序设计 读书笔记之十一 内置对象Global
2012/03/07 Javascript
javascript跑马灯悬停放大效果实现代码
2012/12/12 Javascript
javascript字母大小写转换的4个函数详解
2014/05/09 Javascript
jQuery CSS()方法改变现有的CSS样式
2014/08/20 Javascript
2014 HTML5/CSS3热门动画特效TOP10
2014/12/07 Javascript
jQuery实现仿新浪微博浮动的消息提示框(可智能定位)
2015/10/10 Javascript
JQuery日历插件My97DatePicker日期范围限制
2016/01/20 Javascript
JS+CSS实现的漂亮渐变背景特效代码(6个渐变效果)
2016/03/25 Javascript
基于vue实现可搜索下拉框定制组件
2020/03/26 Javascript
详解React 的几种条件渲染以及选择
2018/10/23 Javascript
详解小程序不同页面之间通讯的解决方案
2018/11/23 Javascript
简单两步使用node发送qq邮件的方法
2019/03/01 Javascript
Javascript 对象(object)合并操作实例分析
2019/07/30 Javascript
Vue 通过公共字段,拼接两个对象数组的实例
2019/11/07 Javascript
[00:21]DOTA2亚洲邀请赛 Logo演绎
2015/02/07 DOTA
[00:15]TI9观赛名额抽取
2019/07/10 DOTA
python刷投票的脚本实现代码
2014/11/08 Python
python使用点操作符访问字典(dict)数据的方法
2015/03/16 Python
Python解惑之整数比较详解
2017/04/24 Python
python 判断是否为正小数和正整数的实例
2017/07/23 Python
python多线程同步实例教程
2019/08/11 Python
Python参数传递机制传值和传引用原理详解
2020/05/22 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
Jupyter notebook命令和编辑模式常用快捷键汇总
2020/11/17 Python
Django2.1.7 查询数据返回json格式的实现
2020/12/29 Python
Bealls Florida百货商店:生活服饰、家居装饰和鞋子
2018/02/23 全球购物
国企干部对照检查材料
2014/08/22 职场文书
党员个人公开承诺书
2014/08/29 职场文书
2014个人年度工作总结
2014/12/15 职场文书
2015年城管个人工作总结范文
2015/04/20 职场文书
工作建议书范文
2019/07/08 职场文书
MySQL 使用索引扫描进行排序
2021/06/20 MySQL
Nginx如何获取自定义请求header头和URL参数详解
2022/07/23 Servers