我试图了解 react-redux 的 connect 方法,以及它作为参数的函数。特别是mapStateToProps()
。
根据我的理解, 的返回值mapStateToProps
将是从状态派生的对象(因为它存在于商店中),其键将作为props传递给您的目标组件(应用了组件连接)。
这意味着您的目标组件使用的状态可能与存储在您的商店中的状态具有截然不同的结构。
问:这样好吗?
问:这是预期的吗?
问:这是一种反模式吗?
我试图了解 react-redux 的 connect 方法,以及它作为参数的函数。特别是mapStateToProps()
。
根据我的理解, 的返回值mapStateToProps
将是从状态派生的对象(因为它存在于商店中),其键将作为props传递给您的目标组件(应用了组件连接)。
这意味着您的目标组件使用的状态可能与存储在您的商店中的状态具有截然不同的结构。
问:这样好吗?
问:这是预期的吗?
问:这是一种反模式吗?
是的,它是正确的。它只是一个帮助函数,可以更简单地访问您的状态属性
想象一下posts
,您的应用中有一个密钥state.posts
state.posts //
/*
{
currentPostId: "",
isFetching: false,
allPosts: {}
}
*/
和组件 Posts
默认情况下connect()(Posts)
将使所有状态props可用于连接的组件
const Posts = ({posts}) => (
<div>
{/* access posts.isFetching, access posts.allPosts */}
</div>
)
现在,当您将 映射state.posts
到您的组件时,它会变得更好一些
const Posts = ({isFetching, allPosts}) => (
<div>
{/* access isFetching, allPosts directly */}
</div>
)
connect(
state => state.posts
)(Posts)
mapDispatchToProps
通常你必须写 dispatch(anActionCreator())
用bindActionCreators
你能做到这一点也更容易喜欢
connect(
state => state.posts,
dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)
)(Posts)
现在你可以在你的组件中使用它
const Posts = ({isFetching, allPosts, fetchPosts, deletePost }) => (
<div>
<button onClick={() => fetchPosts()} />Fetch posts</button>
{/* access isFetching, allPosts directly */}
</div>
)
actionCreator 的一个例子: deletePost
const deletePostAction = (id) => ({
action: 'DELETE_POST',
payload: { id },
})
所以,bindActionCreators
只会采取你的行动,把它们包装成dispatch
电话。(我没有阅读 redux 的源代码,但实现可能是这样的:
const bindActionCreators = (actions, dispatch) => {
return Object.keys(actions).reduce(actionsMap, actionNameInProps => {
actionsMap[actionNameInProps] = (...args) => dispatch(actions[actionNameInProps].call(null, ...args))
return actionsMap;
}, {})
}
问:Is this ok?
答:是的
问:Is this expected?
是的,这是意料之中的(如果您使用的是 react-redux)。
Q: Is this an anti-pattern?
A: 不,这不是反模式。
这称为“连接”您的组件或“使其变得智能”。这是设计使然。
它允许您将组件与状态分离额外的时间,从而增加代码的module化。它还允许您将组件状态简化为应用程序状态的一个子集,这实际上有助于您遵守 Redux 模式。
可以这样想:商店应该包含 应用程序的整个状态。
对于大型应用程序,这可能包含嵌套许多层的数十个属性。
您不想在每次通话时都拖着所有这些(昂贵)。
如果没有它mapStateToProps
或它的一些类似物,你会很想用另一种方式来划分你的状态来提高性能/简化。
你做对了第一部分:
YesmapStateToProps
将 Store 状态作为参数/参数(由 提供react-redux::connect
),并用于将组件与 store 状态的某些部分联系起来。
通过链接,我的意思是返回的对象mapStateToProps
将在构建时作为props提供,任何后续更改都可以通过componentWillReceiveProps
.
如果你知道观察者设计模式,它就是它的那个或它的小变化。
一个例子将有助于使事情更清楚:
import React, {
Component,
} from 'react-native';
class ItemsContainer extends Component {
constructor(props) {
super(props);
this.state = {
items: props.items, //provided by connect@mapStateToProps
filteredItems: this.filterItems(props.items, props.filters),
};
}
componentWillReceiveProps(nextProps) {
this.setState({
filteredItems: this.filterItems(this.state.items, nextProps.filters),
});
}
filterItems = (items, filters) => { /* return filtered list */ }
render() {
return (
<View>
// display the filtered items
</View>
);
}
}
module.exports = connect(
//mapStateToProps,
(state) => ({
items: state.App.Items.List,
filters: state.App.Items.Filters,
//the State.App & state.App.Items.List/Filters are reducers used as an example.
})
// mapDispatchToProps, that's another subject
)(ItemsContainer);
可以有另一个称为itemsFilters
处理显示并将过滤器状态持久化为 Redux Store 状态的react 组件,Demo 组件正在“侦听”或“订阅”Redux Store 状态过滤器,因此每当过滤器存储状态更改时(在 的帮助下filtersComponent
)react -redux检测,有一个变化,并通知或通过发送改变他们的“出版”的所有监听/订阅组件componentWillReceiveProps
在这个例子中会触发项目的重新过滤并刷新显示,由于该react状态已经改变的事实.
如果该示例令人困惑或不够清楚以提供更好的解释,请告诉我。
至于:这意味着您的目标组件使用的状态可能与存储在您的商店中的状态具有截然不同的结构。
我没有得到问题,但只知道react状态 ( this.setState
) 与 Redux Store 状态完全不同!
react 状态用于处理 react 组件的重绘和行为。react状态仅包含在组件中。
Redux Store 状态是 Redux reducers 状态的组合,每个状态负责管理一小部分应用程序逻辑。这些 reducers 属性可以在react-redux::connect@mapStateToProps
任何组件的帮助下访问!这使得 Redux 存储状态可在应用程序范围内访问,而组件状态是其自身独有的。
这个react & redux示例基于 Mohamed Mellouki 的示例。但使用美化和linting 规则进行验证。请注意,我们使用PropTypes定义了我们的 props 和dispatch方法,以便我们的编译器不会对我们尖叫。这个例子还包括一些在 Mohamed 的例子中遗漏的代码行。要使用 connect,您需要从react-redux导入它。此示例还绑定了 filterItems 方法,这将防止组件中的范围问题。此源代码已使用 JavaScript Prettify自动格式化。
import React, { Component } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
class ItemsContainer extends Component {
constructor(props) {
super(props);
const { items, filters } = props;
this.state = {
items,
filteredItems: filterItems(items, filters),
};
this.filterItems = this.filterItems.bind(this);
}
componentWillReceiveProps(nextProps) {
const { itmes } = this.state;
const { filters } = nextProps;
this.setState({ filteredItems: filterItems(items, filters) });
}
filterItems = (items, filters) => {
/* return filtered list */
};
render() {
return <View>/*display the filtered items */</View>;
}
}
/*
define dispatch methods in propTypes so that they are validated.
*/
ItemsContainer.propTypes = {
items: PropTypes.array.isRequired,
filters: PropTypes.array.isRequired,
onMyAction: PropTypes.func.isRequired,
};
/*
map state to props
*/
const mapStateToProps = state => ({
items: state.App.Items.List,
filters: state.App.Items.Filters,
});
/*
connect dispatch to props so that you can call the methods from the active props scope.
The defined method `onMyAction` can be called in the scope of the componets props.
*/
const mapDispatchToProps = dispatch => ({
onMyAction: value => {
dispatch(() => console.log(`${value}`));
},
});
/* clean way of setting up the connect. */
export default connect(mapStateToProps, mapDispatchToProps)(ItemsContainer);
此示例代码是一个很好的模板,可作为组件的起点。
React-Redux connect
用于为每个操作更新存储。
import { connect } from 'react-redux';
const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App);
export default AppContainer;
在这个博客中非常简单明了地解释了。
您可以克隆 github 项目或复制粘贴该博客中的代码以了解 Redux 连接。