使用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 应用代码 方便的排序功能
Feb 06 Javascript
jquery实现的鼠标拖动排序Li或Table
May 04 Javascript
ajaxFileUpload.js插件支持多文件上传的方法
Sep 02 Javascript
使用jquery操作session方法分享
Jan 22 Javascript
jQuery遮罩层实现方法实例详解(附遮罩层插件)
Dec 08 Javascript
jquery插件ajaxupload实现文件上传操作
Dec 09 Javascript
如何消除inline-block属性带来的标签间间隙
Mar 31 Javascript
JQuery中attr属性和jQuery.data()学习笔记【必看】
May 18 Javascript
Js操作DOM元素及获取浏览器高宽的简单方法
Sep 08 Javascript
浅谈JS验证表单文本域输入空格的问题
Feb 14 Javascript
jQuery实现拖动效果的实例代码
Jun 25 jQuery
TypeScript高级用法的知识点汇总
Dec 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
6种php上传图片重命名的方法实例
2013/11/04 PHP
PHP如何获取当前主机、域名、网址、路径、端口等参数
2017/06/09 PHP
javascript与asp.net(c#)互相调用方法
2009/12/13 Javascript
javascript showModalDialog模态对话框使用说明
2009/12/31 Javascript
javascript中的缓动效果实现程序
2012/12/29 Javascript
JS 如何获取radio选中后的值及不选择取radio的值
2013/10/28 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(jquery)
2014/11/16 Javascript
再分享70+免费的jquery 图片滑块效果插件和教程
2014/12/15 Javascript
jQuery的promise与deferred对象在异步回调中的作用
2016/05/03 Javascript
AngularJS基础 ng-switch 指令简单示例
2016/08/03 Javascript
Js 获取、判断浏览器版本信息的简单方法
2016/08/08 Javascript
js阻止冒泡和默认事件(默认行为)详解
2016/10/20 Javascript
jquery select2的使用心得(推荐)
2016/12/04 Javascript
Node.js复制文件的方法示例
2016/12/29 Javascript
利用JS动态生成隔行换色HTML表格的两种方法
2018/10/09 Javascript
vue百度地图 + 定位的详解
2019/05/13 Javascript
vue项目中使用bpmn-自定义platter的示例代码
2020/05/11 Javascript
利用webpack理解CommonJS和ES Modules的差异区别
2020/06/16 Javascript
让python的Cookie.py模块支持冒号做key的方法
2010/12/28 Python
python简单程序读取串口信息的方法
2015/03/13 Python
详解Python的Django框架中的通用视图
2015/05/04 Python
Python的面向对象编程方式学习笔记
2016/07/12 Python
对Python正则匹配IP、Url、Mail的方法详解
2018/12/25 Python
python虚拟环境完美部署教程
2019/08/06 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
解决Python中导入自己写的类,被划红线,但不影响执行的问题
2020/07/13 Python
Python实现JS解密并爬取某音漫客网站
2020/10/23 Python
HTML5的一个显示电池状态的API简介
2015/06/18 HTML / CSS
Sahajan美国:阿育吠陀护肤品牌
2021/01/09 全球购物
Jowissa官方网站:瑞士制造的手表,优雅简约的设计
2020/07/29 全球购物
Can a struct inherit from another struct? (结构体能继承结构体吗)
2016/09/25 面试题
政法学院毕业生求职信
2014/02/28 职场文书
祖国在我心中演讲稿500字
2014/05/04 职场文书
找工作求职信
2014/07/07 职场文书
2014法制宣传日活动总结范文
2014/11/01 职场文书
介绍信格式
2015/01/30 职场文书