使用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 validate poshytip 自定义样式
Nov 26 Javascript
js加载之使用DOM方法动态加载Javascript文件
Nov 08 Javascript
input标签内容改变的触发事件介绍
Jun 18 Javascript
node.js中的path.dirname方法使用说明
Dec 09 Javascript
jQuery大于号(&gt;)选择器的作用解释
Jan 13 Javascript
Javascript类型转换的规则实例解析
Feb 23 Javascript
angular2使用简单介绍
Mar 01 Javascript
基于LayUI实现前端分页功能的方法
Jul 22 Javascript
webpack4 处理SCSS的方法示例
Sep 03 Javascript
express中static中间件的具体使用方法
Oct 17 Javascript
JavaScript 常见的继承方式汇总
Sep 17 Javascript
vue-cli 3如何使用vue-bootstrap-datetimepicker日期插件
Feb 20 Vue.js
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 和 MySQL 基础教程(一)
2006/10/09 PHP
Laravel 4.2 中队列服务(queue)使用感受
2014/10/30 PHP
浅谈PHP面向对象之访问者模式+组合模式
2017/05/22 PHP
php session_decode函数用法讲解
2019/05/26 PHP
prototype.js的Ajax对象
2006/09/23 Javascript
JQuery live函数
2010/12/24 Javascript
JavaScript中具名函数的多种调用方式总结
2014/11/08 Javascript
JS获取iframe中longdesc属性的方法
2015/04/01 Javascript
AngularJS快速入门
2015/04/02 Javascript
javascript 使用for循环时该注意的问题-附问题总结
2015/08/19 Javascript
谈谈Jquery ajax中success和complete有哪些不同点
2015/11/20 Javascript
jquery常用的12个小功能
2016/07/22 Javascript
使用nvm管理不同版本的node与npm的方法
2017/10/31 Javascript
微信小程序实现页面跳转传值以及获取值的方法分析
2017/12/18 Javascript
vue.js使用watch监听路由变化的方法
2018/07/08 Javascript
JS实现点击生成UUID的方法完整实例【基于jQuery】
2019/06/12 jQuery
Vue 子组件与数据传递问题及注意事项
2019/07/11 Javascript
vue实现滑动到底部加载更多效果
2020/10/27 Javascript
微信小程序 scroll-view 水平滚动实现过程解析
2019/10/12 Javascript
Python获取文件所在目录和文件名的方法
2017/01/12 Python
Python中生成Epoch的方法
2017/04/26 Python
使用Python处理BAM的方法
2018/09/28 Python
三步实现Django Paginator分页的方法
2019/06/11 Python
python实现知乎高颜值图片爬取
2019/08/12 Python
在django模板中实现超链接配置
2019/08/21 Python
Python类如何定义私有变量
2020/02/03 Python
Links of London官方网站:英国标志性的珠宝品牌
2017/04/09 全球购物
西雅图电动自行车公司:Rad Power Bikes
2020/02/02 全球购物
C++面试题:关于链表和指针
2013/06/05 面试题
什么是组件架构
2016/05/15 面试题
《四季》教学反思
2014/04/08 职场文书
2014年社区党建工作汇报材料
2014/11/02 职场文书
2015年党员创先争优公开承诺书
2015/04/27 职场文书
2015年留守儿童工作总结
2015/05/22 职场文书
环保建议书范文
2015/09/14 职场文书
成功的商业计划书这样写才最靠谱
2019/07/12 职场文书