使用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实现动态CSS换肤技术的脚本
Jun 29 Javascript
出现“不能执行已释放的Script代码”错误的原因及解决办法
Aug 29 Javascript
js实现幻灯片效果(基于jquery插件)
Nov 05 Javascript
jquery交替变换颜色的三种方法 实例代码
Nov 19 Javascript
Js保留小数点的4种效果实现代码分享
Apr 12 Javascript
jQuery操作cookie方法实例教程
Nov 25 Javascript
Node.js中安全调用系统命令的方法(避免注入安全漏洞)
Dec 05 Javascript
Ionic3 UI组件之Gallery Modal详解
Jun 07 Javascript
JS实现用特殊符号替换字符串的中间部分区域的实例代码
Jul 24 Javascript
vuejs前后端数据交互之从后端请求数据的实例
Aug 11 Javascript
详解关于表格合并span-method方法的补充(表格数据由后台动态返回)
May 21 Javascript
vue 根据选择条件显示指定参数的例子
Nov 09 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中实现汉字转区位码应用源码实例解析
2010/06/14 PHP
JSON在PHP中的应用介绍
2012/09/08 PHP
采用memcache在web集群中实现session的同步会话
2014/07/05 PHP
PHP获取客户端真实IP地址的5种情况分析和实现代码
2014/07/08 PHP
AES加解密在php接口请求过程中的应用示例
2016/10/26 PHP
php解决crontab定时任务不能写入文件问题的方法分析
2019/09/16 PHP
一段多浏览器的&quot;复制到剪贴板&quot;javascript代码
2007/03/27 Javascript
Javascript 阻止javascript事件冒泡,获取控件ID值
2009/06/27 Javascript
利用jQuery实现可输入搜索文字的下拉框
2013/10/23 Javascript
浅谈JavaScript中null和undefined
2015/07/09 Javascript
阿里巴巴技术文章分享 Javascript继承机制的实现
2016/01/14 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
shiro授权的实现原理
2017/09/21 Javascript
详解vue-cli快速构建vue应用并实现webpack打包
2017/12/13 Javascript
用js简单提供增删改查接口
2019/05/12 Javascript
layui自定义ajax左侧三级菜单
2019/07/26 Javascript
微信小程序 可搜索的地址选择实现详解
2019/08/28 Javascript
JS实现简单日历特效
2020/01/03 Javascript
前端 javascript 实现文件下载的示例
2020/11/24 Javascript
[02:32]DOTA2英雄基础教程 祸乱之源
2013/12/23 DOTA
在Docker上部署Python的Flask框架的教程
2015/04/08 Python
Python抓取框架Scrapy爬虫入门:页面提取
2017/12/01 Python
使用Python实现批量ping操作方法
2020/05/06 Python
python和php学习哪个更有发展
2020/06/17 Python
澳大利亚优惠网站:Deals.com.au
2019/07/02 全球购物
iHerb俄罗斯:维生素、补品和天然产品
2020/07/09 全球购物
电气自动化个人求职信范文
2014/02/03 职场文书
会计专业导师推荐信
2014/03/08 职场文书
售后求职信范文
2014/03/15 职场文书
大学生村官承诺书
2014/03/28 职场文书
房屋买卖协议书范本
2014/09/27 职场文书
党员“四风”问题批评与自我批评思想汇报
2014/10/06 职场文书
先进人物事迹材料
2014/12/29 职场文书
基层医务人员三严三实心得体会
2016/01/05 职场文书
Python深度学习之实现卷积神经网络
2021/06/05 Python
MySQL插入数据与查询数据
2022/03/25 MySQL