javascript - 链 connect/mapStateToProps/mapDispatchToProps 函数用于 react-redux 中的代码重用
问题描述
假设我有两个 redux 连接的组件。第一个是一个简单的 todo 加载/显示容器,将以下函数传递给connect()
; mapStateToProps
从 redux state 中读取 todos,并mapDispatchToProps
用于请求 state 提供来自服务器的最新 todos 列表:
TodoWidgetContainer.js
import TodoWidgetDisplayComponent from '...'
function mapStateToProps(state) {
return {
todos: todoSelectors.getTodos(state)
};
}
function mapDispatchToProps(dispatch) {
return {
refreshTodos: () => dispatch(todoActions.refreshTodos())
};
}
connect(mapStateToProps, mapDispatchTo)(TodoWidgetDisplayComponent);
第二个 redux 组件旨在应用于页面上的任何组件,以便组件可以指示是否显示全局“加载”图标。由于这可以在任何地方使用,我创建了一个辅助函数,它包装MapDispatchToProps
在一个闭包中并为每个组件生成一个 ID,用于确保请求加载器的所有组件都表明它们不再需要它,并且全局loader 可以隐藏。
功能基本上如下,mapStateToProps
将加载器的可见性暴露给组件,并mapDispatchToProps
允许它们请求加载器显示或隐藏。
加载.js
function mapStateToProps(state) {
return {
openLoader: loaderSelectors.getLoaderState(state)
};
}
function mapDispatchToProps() {
const uniqId = v4();
return function(dispatch) {
return {
showLoader: () => {
dispatch(loaderActions.showLoader(uniqId));
},
hideLoader: () => {
dispatch(loaderActions.hideLoader(uniqId));
}
};
};
}
export default function Loadify(component) {
return connect(mapStateToProps, mapDispatchToProps())(component);
}
所以现在,如果我有一个想要访问加载器的组件,我可以做这样的事情:
import Loadify from '...'
class DisplayComponent = new React.Component { ... }
export default Loadify(DisplayComponent);
它应该给它一个唯一的ID,允许它请求加载器显示/隐藏,只要有一个组件请求它显示,加载器图标就会显示。到目前为止,这一切似乎都运行良好。
我的问题是,如果我想将其应用于 todos 组件,以便该组件可以请求/接收其 todos,同时还允许请求加载程序在处理时显示,我可以执行以下操作:
TodoWidgetContainer.js
import Loadify from '...'
import TodoWidgetDisplayComponent from '...'
function mapStateToProps(state) {
return {
todos: todoSelectors.getTodos(state)
};
}
function mapDispatchToProps(dispatch) {
return {
refreshTodos: () => dispatch(todoActions.refreshTodos())
};
}
const TodoContainer = connect(mapStateToProps, mapDispatchTo)(TodoWidgetDisplayComponent);
export default Loadify(TodoContainer);
假设没有重复的键,redux 会自动将对象合并在一起以使它们兼容吗?还是只需要最近的一组mapStateToProps
/mapDispatchTo
除非我进行某种手动合并?或者有没有更好的方法来获得这种我没有看到的可重用性?我真的宁愿避免为我们需要的每个组件创建一组自定义容器。
解决方案
好吧,这就是我要做的。创建一个高阶组件(HOC),为你的减速器添加一个新的微调器引用。HOC 将通过绑定到生命周期方法来初始化和销毁对 redux 中微调器的引用。HOC 将为基础组件提供两个属性。第一个是isLoading
接受布尔参数的函数;true 开启,false 关闭。第二个属性是spinnerState
微调器当前状态的只读布尔值。
我在没有动作创建者或减速器的情况下创建了这个示例,如果您需要它们的示例,请告诉我。
加载.jsx
/*---------- Vendor Imports ----------*/
import React from 'react';
import { connect } from 'react-redux';
import v4 from 'uuid/v4';
/*---------- Action Creators ----------*/
import {
initNewSpinner,
unloadSpinner,
toggleSpinnerState,
} from '@/wherever/your/actions/are'
const loadify = (Component) => {
class Loadify extends React.Component {
constructor(props) {
super(props);
this.uniqueId = v4();
props.initNewSpinner(this.uniqueId);;
this.isLoading = this.isLoading.bind(this);
}
componentWillMount() {
this.props.unloadSpinner(this.uniqueId);
}
// true is loading, false is not loading
isLoading(isOnBoolean) {
this.props.toggleSpinner(this.uniqueId, isOnBoolean);
}
render() {
// spinners is an object with the uuid as it's key
// the value to the key is weather or not the spinner is on.
const { spinners } = this.props;
const spinnerState = spinners[this.uniqueId];
return (
<Component isLoading={this.isLoading} spinnerState={spinnerState} />
);
}
}
const mapStateTopProps = state => ({
spinners: state.ui.spinners,
});
const mapDispatchToProps = dispatch => ({
initNewSpinner: uuid => dispatch(initNewSpinner(uuid)),
unloadSpinner: uuid => dispatch(unloadSpinner(uuid)),
toggleSpinner: (uuid, isOn) => dispatch(toggleSpinnerState(uuid, isOn))
})
return connect(mapStateTopProps, mapDispatchToProps)(Loadify);
};
export default loadify;
用例示例
import loadify from '@/location/loadify';
import Spinner from '@/location/SpinnerComponent';
class Todo extends Component {
componentWillMount() {
this.props.isLoading(true);
asyncCall.then(response => {
// process response
this.props.isLoading(false);
})
}
render() {
const { spinnerState } = this.props;
return (
<div>
<h1>Spinner Testing Component</h1>
{ spinnerState && <Spinner /> }
</div>
);
}
}
// Use whatever state you need
const mapStateToProps = state => ({
whatever: state.whatever.youneed,
});
// use whatever dispatch you need
const mapDispatchToProps = dispatch => ({
doAthing: () => dispatch(doAthing()),
});
// Export enhanced Todo Component
export default loadify(connect(mapStateToProps, mapDispatchToProps)(Todo));
推荐阅读
- c# - 实施 Xbox Live 服务时出现错误 0x87DD0005
- javascript - 给定一组“狗”、“猫”和“水”,编写一个函数。称为分离,它返回一个新数组,所以狗是 sep。从猫的水
- ios - 向 NavigationBar SwiftUI 添加不透明度
- python - 来自一维张量的 Pytorch CrossEntropyLoss
- next.js - Nextjs & Apollo:在 getInitialProps 服务器端将 cookie 附加到 Apollo 客户端
- java - Issues authenticating a post request with a certificate and private key in Kotlin / Java
- html - List-item fixed width not working properly
- c# - Console.Write() without delay / lag
- python - 为聚合创建临时列
- python - Python cursor how do I replace with a string and maintain quotation marks in a SQL que?y