使用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 相关文章推荐
jQuery插件开发全解析
Oct 10 Javascript
JS Array.slice 截取数组的实现方法
Jan 02 Javascript
一款简单的jQuery图片标注效果附源码下载
Mar 22 Javascript
js日期相关函数dateAdd,dateDiff,dateFormat等介绍
Sep 24 Javascript
javascript中replace使用方法总结
Mar 01 Javascript
react-router中的属性详解
Jun 01 Javascript
Vue 2.0的数据依赖实现原理代码简析
Jul 10 Javascript
vue-infinite-loading2.0 中文文档详解
Apr 08 Javascript
基于游标的分页接口实现代码示例
Nov 12 Javascript
跨域解决之JSONP和CORS的详细介绍
Nov 21 Javascript
原生JavaScript实现滑动拖动验证的示例代码
Dec 06 Javascript
用vue 实现手机触屏滑动功能
May 28 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中spl_autoload详解
2014/10/17 PHP
PHP+Ajax+JS实现多图上传
2016/05/07 PHP
一个简单的php MVC留言本实例代码(必看篇)
2016/09/22 PHP
详解PHP序列化和反序列化原理
2018/01/15 PHP
原来Jquery.load的方法可以一直load下去
2011/03/28 Javascript
基于jquery的loading 加载提示效果实现代码
2011/09/01 Javascript
Redis基本知识、安装、部署、配置笔记
2015/03/05 Javascript
深入浅析AngularJS和DataModel
2016/02/16 Javascript
javascript常见数字进制转换实例分析
2016/04/21 Javascript
利用React-router+Webpack快速构建react程序
2016/10/27 Javascript
使用ionic切换页面卡顿的解决方法
2016/12/16 Javascript
jQuery文字轮播特效
2017/02/12 Javascript
vue计算属性及使用详解
2018/04/02 Javascript
详解微信JS-SDK选择图片遇到的坑
2018/08/15 Javascript
Javascript读写cookie的实例源码
2019/03/16 Javascript
如何在JavaScript中创建具有多个空格的字符串?
2020/02/23 Javascript
解决vue项目 build之后资源文件找不到的问题
2020/09/12 Javascript
[06:13]DOTA2进化论(修改版)
2013/10/08 DOTA
python实现解数独程序代码
2017/04/12 Python
Python3实现转换Image图片格式
2018/06/21 Python
对Python中内置异常层次结构详解
2018/10/18 Python
Numpy之random函数使用学习
2019/01/29 Python
python 操作hive pyhs2方式
2019/12/21 Python
python利用opencv保存、播放视频
2020/11/02 Python
Python代码覆盖率统计工具coverage.py用法详解
2020/11/25 Python
用HTML5的canvas实现一个炫酷时钟效果
2016/05/20 HTML / CSS
馥蕾诗美国官网:Fresh美国
2019/10/09 全球购物
巴西最大的玩具连锁店:Ri Happy
2020/06/17 全球购物
开放系统互连参考模型
2016/06/29 面试题
门卫岗位安全职责
2013/12/13 职场文书
安全协议书范本
2014/04/21 职场文书
三严三实对照检查材料
2014/08/25 职场文书
个人工作保证书
2015/02/28 职场文书
Mysql基础之常见函数
2021/04/22 MySQL
使用php的mail()函数实现发送邮件功能
2021/06/03 PHP
Python Django / Flask如何使用Elasticsearch
2022/04/19 Python