使用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中,为什么要尽可能使用局部变量?
Apr 06 Javascript
JS遮罩层效果 兼容ie firefox jQuery遮罩层
Jul 26 Javascript
Javascript中克隆一个数组的实现代码
Dec 06 Javascript
浅谈nodeName,nodeValue,nodeType,typeof 的区别
Jan 13 Javascript
JavaScript基础篇(6)之函数表达式闭包
Dec 11 Javascript
14 个折磨人的 JavaScript 面试题
Aug 08 Javascript
微信小程序 Tab页切换更新数据
Jan 05 Javascript
Three.js 再探 - 写一个微信跳一跳极简版游戏
Jan 04 Javascript
vue2.0$nextTick监听数据渲染完成之后的回调函数方法
Sep 11 Javascript
JavaScript惰性求值的一种实现方法示例
Jan 11 Javascript
Node Express用法详解【安装、使用、路由、中间件、模板引擎等】
May 13 Javascript
vue中v-for循环选中点击的元素并对该元素添加样式操作
Jul 17 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 IF ELSE简化/三元一次式的使用
2011/08/22 PHP
修改apache配置文件去除thinkphp url中的index.php
2014/01/17 PHP
ThinkPHP CURD方法之data方法详解
2014/06/18 PHP
分享自定义的几个PHP功能函数
2015/04/15 PHP
Yii模型操作之criteria查找数据库的方法
2016/07/15 PHP
php将文件夹打包成zip文件的简单实现方法
2016/10/04 PHP
Laravel下生成验证码的类
2017/11/15 PHP
js removeChild 障眼法 可能出现的错误
2009/10/06 Javascript
为JavaScript添加重载函数的辅助方法
2010/07/04 Javascript
JS鼠标滑过图片时切换图片实现思路
2013/09/12 Javascript
JavaScript中原型和原型链详解
2015/02/11 Javascript
JS中this上下文对象使用方式
2016/10/09 Javascript
BootStrap daterangepicker 双日历控件
2017/06/02 Javascript
jQuery EasyUI 选项卡面板tabs的使用实例讲解
2017/12/25 jQuery
基于jquery.page.js实现分页效果
2018/01/01 jQuery
Vue前后端不同端口的实现方法
2018/09/19 Javascript
laravel-admin 与 vue 结合使用实例代码详解
2019/06/04 Javascript
JavaScript内置对象math,global功能与用法实例分析
2019/06/10 Javascript
Vue.js中的extend绑定节点并显示的方法
2019/06/20 Javascript
解决layui的input独占一行的问题
2019/09/10 Javascript
JS实现拼图游戏
2021/01/29 Javascript
js String.prototype.trim字符去前后空格的扩展
2020/08/23 Javascript
Python应用库大全总结
2018/05/30 Python
pyqt5中动画的使用详解
2020/04/01 Python
python3通过udp实现组播数据的发送和接收操作
2020/05/05 Python
在线服装零售商:SheIn
2016/07/22 全球购物
党员干部承诺书范文
2014/03/25 职场文书
爱护公共设施的标语
2014/06/24 职场文书
公司委托书格式
2014/08/01 职场文书
个人工作表现评价材料
2014/09/21 职场文书
交通事故赔偿起诉书
2015/05/20 职场文书
干货:我将这样书写我的演讲稿!
2019/05/09 职场文书
工作报告范文
2019/06/20 职场文书
Python中的xlrd模块使用整理
2021/06/15 Python
正则表达式拆分url实例代码
2022/02/24 Java/Android
Python内置类型集合set和frozenset的使用详解
2022/04/26 Python