使用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 相关文章推荐
js cookies实现简单统计访问次数
Nov 24 Javascript
精通Javascript系列之Javascript基础篇
Jun 07 Javascript
jQuery中[attribute!=value]选择器用法实例
Dec 31 Javascript
js获取数组的最后一个元素
Apr 14 Javascript
在Html中使用Requirejs进行模块化开发实例详解
Apr 15 Javascript
vue2.0+webpack环境的构造过程
Nov 08 Javascript
详解PHP中pathinfo()函数导致的安全问题
Jan 05 Javascript
javascript实现二叉树的代码
Jun 08 Javascript
如何使用JS在HTML中自定义字符串格式化
Jul 20 Javascript
JS实现按钮颜色切换效果
Sep 05 Javascript
对layer弹出框中icon数字参数的说明介绍
Sep 04 Javascript
js单线程的本质 Event Loop解析
Oct 29 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操作MongoDB时的整数问题及对策说明
2011/05/02 PHP
ThinkPHP公共配置文件与各自项目中配置文件组合的方法
2014/11/24 PHP
PHP在线书签系统分享
2016/01/04 PHP
PHP实现文字写入图片功能
2019/02/18 PHP
20个非常棒的Jquery实用工具 国外文章
2010/01/01 Javascript
Jquery 滑入滑出效果实现代码
2010/03/27 Javascript
JS跨域总结
2012/08/30 Javascript
javascript间隔定时器(延时定时器)学习 间隔调用和延时调用
2014/01/13 Javascript
JavaScript和HTML DOM的区别与联系及Javascript和DOM的关系
2015/11/15 Javascript
jQuery判断checkbox选中状态
2016/05/12 Javascript
深入理解JavaScript中的call、apply、bind方法的区别
2016/05/30 Javascript
用jquery获取自定义的标签属性的值简单实例
2016/09/17 Javascript
JavaScript获取URL中参数querystring的方法详解
2016/10/11 Javascript
vue.js开发环境搭建教程
2017/05/04 Javascript
JavaScript实现滑动导航栏效果
2017/08/30 Javascript
Vue项目中设置背景图片方法
2018/02/21 Javascript
详解Eslint 配置及规则说明
2018/09/10 Javascript
Node.js npm命令运行node.js脚本的方法
2018/10/10 Javascript
javascript中this的用法实践分析
2019/07/29 Javascript
如何在微信小程序中存setStorage
2019/12/13 Javascript
Nuxt默认模板、默认布局和自定义错误页面的实现
2020/05/11 Javascript
jquery+css3实现的经典弹出层效果示例
2020/05/16 jQuery
vue之封装多个组件调用同一接口的案例
2020/08/11 Javascript
Vue中关闭弹窗组件时销毁并隐藏操作
2020/09/01 Javascript
python操作mysql数据库
2017/03/05 Python
python ddt实现数据驱动
2018/03/14 Python
更新pip3与pyttsx3文字语音转换的实现方法
2019/08/08 Python
python3反转字符串的3种方法(小结)
2019/11/07 Python
如何解决flask修改静态资源后缓存文件不能及时更改问题
2020/08/02 Python
基础的CSS3弹性盒Flexbox布局使用实例
2016/04/08 HTML / CSS
弘扬雷锋精神活动演讲稿
2014/03/04 职场文书
小学英语复习计划
2015/01/19 职场文书
亲属关系公证书样本
2015/01/23 职场文书
2015年医务科工作总结范文
2015/05/26 职场文书
Vue实现跑马灯样式文字横向滚动
2021/11/23 Vue.js
Java异常处理try catch的基本用法
2021/12/06 Java/Android