用技术改变生活, 用生活完善技术. 来自微播易一枚向全栈方向努力奔跑的前端工程师.
微信同步: wDxKn89
前言
组件隔离适用范围 同一个页面引用多个相同的自定义公共组件 (该类组件拥有自己的 Redux) 并且这些组件之间有交互. 案例背景 在一个页面中存在两个相同的公共组件(A), 在页面处理中, 对 A 组件进行操作, 有一些重要的数据被存入到 A 组件的对应的 Redux 中. 如果该页面只存在一个 A 组件, 不管进行如何的操作, 数据都是一份. 但是如果该页面中存在多个 A 组件, 在对第一个 A 组件进行数据处理之后, 数据存入到 Rudex 中. 此时在对另一个 A 组件进行相同的操作步骤, 但是存入的数据和第一个 A 组件的存储在 Redux 中的数据有差别, 此时在第二个 A 组件的操作就会影响第一个 A 组件的数据.
原因: 由于页面中引用的是相同的组件, 在进行数据处理的时候, 都会存在到 Redux 中, 而该组件的 Redux 在内存中只是保存了一份.
这就类似于如下操作
let ob1 = new Object();====== 类似 ===>定义了一个组件
ob1.name = 'haha';========= 类似 ====>进行数据处理的时候, 将组件的一些数据存入到对应的 Redux 中.
============== 华丽的分割线 ==================
ob1.name ="hehe";========= 类似 =====>此处类似于第二个组件进行相同的操作, 将对应的 Redux 中的数据进行了变化, 该变化会影响到上面的代码.
复制代码
利用 Provider
在需要处理组件隔离的页面中引用如下代码
import { Provider } from 'react-redux';[Provider 属于 react-redux](https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store)
import { createStore } from 'redux' ===>用于生成总的 Store
import { Router, browserHistory } from 'react-router';
复制代码
在组件的 constructor 中进行变量的初始化
- export default class PersonComponent extends Component {
- constructor(props,context){
- super(props,context);
this.store1 = createStore(reducer); ===>此处的 reducer 是你自己的页面的 reducer
- }
- render(){
- //....
- }
- }
复制代码
关于 https://github.com/reactjs/redux/blob/master/docs/api/createStore.md 处理需要隔离的组件
- render(){
- <div>
- <A/>
- <Provider store={this.store1}> ===>此处的 store1 是根据你页面的 reducer 构建的
- <A/> ==>此处为需要隔离的组件
- </Provider>
- </div>
- }
复制代码
基于如上操作, 第二个 A 组件被成功的隔离出整个 Store 树之外(换句话说, 该 A 组件自己定义了一套 Store)
但是, 组件隔离是为了在操作之后, 拥有相同的 Redux 的组件在进行相同的操作步骤之后, 互相不被影响. 所以, 需要根据刚才在第二步构建的 Store1 来进行对应的 action 的 dispatch.
this.store1.getState().xxx ===>此处的 xxx 是在 rootReducer.js 中 combineReducers 引用的 A 组件的 Redux 的同名 State(Note: 此处也有对应的方法起一个与 Redux 不同的名字, 自行百度吧)
上面是用于获取 A 组件中 state 数据的,
this.store1.dispatch(yyy(param)) ===>此处的 yyy 是在 A 组件的 ActionCreator (该用法请参考 Redux 官网)
复制代码
上面一行代码用户发送一个 action
利用第三方库 multireducer
multireducer 该库的主要目的就是为了实现组件隔离.
对应的 github 地址 https://github.com/erikras/multireducer 核心思想: A utility to wrap many copies of a single Redux reducer into a single key-based reducer.
项目中引用 multireducer
npm install --save multireducer
复制代码
在组件定义处处理
引用 connectMultireducer
import {connectMultireducer} from 'multireducer';
复制代码
组件与 Redux 进行关联
- @connectMultireducer(
- (key, state) => ({count: state.multireducer[key].count}),
- {increment}
- )
复制代码
此处的处理方式和华南城项目中 @connect 的用法类似 主要的区别在与该方法中第二个参数为需要隔离组件的 redux.js
在组件调用除处理
- <A multireducerKey="1" />
- <A multireducerKey="2" />
- <A multireducerKey="3" />
复制代码
此处在一个页面中引用了三个相同的组件, 有一个 multireducerKey 是必须的, 用于区分组件.(这和 React 在处理 List 等拥有相同数据结构的组件的时候, 需要一个 key 是相同的道理)
处理 Rudecer
在进行 combineReducers 处, 需要指出刚才 multireducerKey 对应的 value 是指的什么
- export default combineReducers({
- routing: routerReducer,
- reduxAsyncConnect,
- multireducer: multireducer({
- 1: XXX,
- 2: XXX,
- 3: XXX
- })
- });
复制代码
此处的格式是固定的, XXX 代表需要进行隔离处理的组件的 Redux, 对应的 1,2,3 就是在步骤 3 处 multireducerKey 的值,(note: 说的是格式固定, 但是其中的参数是可以根据自己的情况进行变化的)
基于如上的 4 步操作就可以将 A 组件进行组件隔离操作了. 原理解释
采用此处的处理方式与第一种处理方式相比, 被隔离的组件没有脱离整个 Store 树, 而是根据 multireducerKey 来判断用户当前操作发送的 action 是来自哪个一个, 然后根据 multireducerKey 进行对应的数据操作处理.
来源: https://juejin.im/post/5b797341e51d45388502fba2