Javascript 理解 React-Redux 和 mapStateToProps()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38202572/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding React-Redux and mapStateToProps()
提问by Pablo Barría Urenda
I'm trying to understand the connect method of react-redux, and the functions it takes as parameters. In particular mapStateToProps()
.
我试图了解 react-redux 的 connect 方法,以及它作为参数的函数。特别是mapStateToProps()
。
The way I understand it, the return value of mapStateToProps
will be an object derived from state (as it lives in the store), whose keys will be passed to your target component (the component connect is applied to) as props.
按照我的理解, 的返回值mapStateToProps
将是从状态派生的对象(因为它存在于商店中),其键将作为道具传递给您的目标组件(应用了组件连接)。
This means that the state as consumed by your target component can have a wildly different structure from the state as it is stored on your store.
这意味着您的目标组件使用的状态可能与存储在您的商店中的状态具有截然不同的结构。
Q: Is this OK?
Q: Is this expected?
Q: Is this an anti-pattern?
问:这样好吗?
问:这是预期的吗?
问:这是一种反模式吗?
采纳答案by Richard Strickland
Q: Is this ok?
A: yes
问:Is this ok?
答:是的
Q: Is this expected?
Yes, this is expected (if you are using react-redux).
问:Is this expected?
是的,这是预期的(如果您使用的是 react-redux)。
Q: Is this an anti-pattern?
A: No, this is not an anti-pattern.
Q: Is this an anti-pattern?
A: 不,这不是反模式。
It's called "connecting" your component or "making it smart". It's by design.
这称为“连接”您的组件或“使其变得智能”。这是设计使然。
It allows you to decouple your component from your state an additional time which increases the modularity of your code. It also allows you to simplify your component state as a subset of your application state which, in fact, helps you comply with the Redux pattern.
它允许您将组件与状态分离额外的时间,从而增加代码的模块化。它还允许您将组件状态简化为应用程序状态的子集,这实际上有助于您遵守 Redux 模式。
Think about it this way: a store is supposed to contain the entirestate of your application.
For large applications, this could contain dozens of properties nested many layers deep.
You don't want to haul all that around on each call (expensive).
可以这样想:商店应该包含 应用程序的整个状态。
对于大型应用程序,这可能包含嵌套许多层的数十个属性。
您不想在每次通话时都拖着所有这些(昂贵)。
Without mapStateToProps
or some analog thereof, you would be tempted to carve up your state another way to improve performance/simplify.
如果没有它mapStateToProps
或它的一些类似物,你会很想用另一种方式来划分你的状态来提高性能/简化。
回答by webdeb
Yes, it is correct. Its just a helper function to have a simpler way to access your state properties
是的,它是正确的。它只是一个帮助函数,可以更简单地访问您的状态属性
Imagine you have a posts
key in your App state.posts
想象一下posts
,您的应用中有一个密钥state.posts
state.posts //
/*
{
currentPostId: "",
isFetching: false,
allPosts: {}
}
*/
And component Posts
和组件 Posts
By default connect()(Posts)
will make all state props available for the connected Component
默认情况下connect()(Posts)
将使所有状态道具可用于连接的组件
const Posts = ({posts}) => (
<div>
{/* access posts.isFetching, access posts.allPosts */}
</div>
)
Now when you map the state.posts
to your component it gets a bit nicer
现在,当您将 映射state.posts
到您的组件时,它会变得更好
const Posts = ({isFetching, allPosts}) => (
<div>
{/* access isFetching, allPosts directly */}
</div>
)
connect(
state => state.posts
)(Posts)
mapDispatchToProps
mapDispatchToProps
normally you have to write dispatch(anActionCreator())
通常你必须写 dispatch(anActionCreator())
with bindActionCreators
you can do it also more easily like
用bindActionCreators
你能做到这一点也更容易喜欢
connect(
state => state.posts,
dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)
)(Posts)
Now you can use it in your Component
现在你可以在你的组件中使用它
const Posts = ({isFetching, allPosts, fetchPosts, deletePost }) => (
<div>
<button onClick={() => fetchPosts()} />Fetch posts</button>
{/* access isFetching, allPosts directly */}
</div>
)
Update on actionCreators..
actionCreators 更新..
An example of an actionCreator: deletePost
actionCreator 的一个例子: deletePost
const deletePostAction = (id) => ({
action: 'DELETE_POST',
payload: { id },
})
So, bindActionCreators
will just take your actions, wrap them into dispatch
call. (I didn't read the source code of redux, but the implementation might look something like this:
所以,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;
}, {})
}
回答by Mohamed Mellouki
You got the first part right:
你做对了第一部分:
Yes mapStateToProps
has the Store state as an argument/param (provided by react-redux::connect
) and its used to link the component with certain part of the store state.
YesmapStateToProps
将 Store 状态作为参数/参数(由 提供react-redux::connect
),并用于将组件与 store 状态的某些部分链接起来。
By linking I mean the object returned by mapStateToProps
will be provided at construction time as props and any subsequent change will be available through componentWillReceiveProps
.
通过链接,我的意思是返回的对象mapStateToProps
将在构建时作为道具提供,任何后续更改都可以通过componentWillReceiveProps
.
If you know the Observer design pattern it's exactly that or small variation of it.
如果你知道观察者设计模式,它就是它的那个或它的小变化。
An example would help make things clearer:
一个例子将有助于使事情更清楚:
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);
There can be another react component called itemsFilters
that handle the display and persisting the filter state into Redux Store state, the Demo component is "listening" or "subscribed" to Redux Store state filters so whenever filters store state changes (with the help of filtersComponent
) react-redux detect that there was a change and notify or "publish" all the listening/subscribed components by sending the changes to their componentWillReceiveProps
which in this example will trigger a refilter of the items and refresh the display due to the fact that react state has changed.
可以有另一个称为itemsFilters
处理显示并将过滤器状态持久化为 Redux Store 状态的react 组件,Demo 组件正在“侦听”或“订阅”Redux Store 状态过滤器,因此每当过滤器存储状态更改时(在 的帮助下filtersComponent
)react -redux检测,有一个变化,并通知或通过发送改变他们的“出版”的所有监听/订阅组件componentWillReceiveProps
在这个例子中会触发项目的重新过滤并刷新显示,由于该反应状态已经改变的事实.
Let me know if the example is confusing or not clear enough to provide a better explanation.
让我知道该示例是否令人困惑或不够清楚以提供更好的解释。
As for: This means that the state as consumed by your target component can have a wildly different structure from the state as it is stored on your store.
至于:这意味着您的目标组件使用的状态可能与存储在您的商店中的状态具有截然不同的结构。
I didn't get the question, but just know that the react state (this.setState
) is totally different from the Redux Store state!
我没有得到问题,但只知道反应状态 ( this.setState
) 与 Redux Store 状态完全不同!
The react state is used to handle the redraw and behavior of the react component. The react state is contained to the the component exclusively.
react 状态用于处理 react 组件的重绘和行为。反应状态仅包含在组件中。
The Redux Store state is a combination of Redux reducers states, each is responsible of managing a small portion app logic. Those reducers attributes can be accessed with the help of react-redux::connect@mapStateToProps
by any component! Which make the Redux store state accessible app wide while component state is exclusive to itself.
Redux Store 状态是 Redux reducers 状态的组合,每个状态负责管理一小部分应用程序逻辑。这些 reducers 属性可以在react-redux::connect@mapStateToProps
任何组件的帮助下访问!这使得 Redux 存储状态可在应用程序范围内访问,而组件状态是其自身独有的。
回答by Patrick W. McMahon
This react& reduxexample is based off Mohamed Mellouki's example. But validates using prettifyand linting rules. Note that we define our props and dispatchmethods using PropTypesso that our compiler doesn't scream at us. This example also included some lines of code that had been missing in Mohamed's example. To use connect you will need to import it from react-redux. This example also bindsthe method filterItems this will prevent scopeproblems in the component. This source code has been auto formatted using JavaScript Prettify.
这个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);
This example code is a good template for a starting place for your component.
此示例代码是一个很好的模板,可作为组件的起点。
回答by ArunValaven
React-Reduxconnect
is used to update store for every actions.
React-Reduxconnect
用于为每个操作更新存储。
import { connect } from 'react-redux';
const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App);
export default AppContainer;
It's very simply and clearly explained in this blog.
在这个博客中非常简单明了地解释了。
You can clone github project or copy paste the code from that blog to understand the Redux connect.
您可以克隆 github 项目或复制粘贴该博客中的代码以了解 Redux 连接。
回答by zloctb
Here's an outline/boilerplate for describing the behavior of mapStateToProps
:
这是用于描述以下行为的大纲/样板mapStateToProps
:
(This is a vastly simplified implementation of what a Redux container does.)
(这是 Redux 容器所做的极大简化的实现。)
class MyComponentContainer extends Component {
mapStateToProps(state) {
// this function is specific to this particular container
return state.foo.bar;
}
render() {
// This is how you get the current state from Redux,
// and would be identical, no mater what mapStateToProps does
const { state } = this.context.store.getState();
const props = this.mapStateToProps(state);
return <MyComponent {...this.props} {...props} />;
}
}
and next
接下来
function buildReduxContainer(ChildComponentClass, mapStateToProps) {
return class Container extends Component {
render() {
const { state } = this.context.store.getState();
const props = mapStateToProps(state);
return <ChildComponentClass {...this.props} {...props} />;
}
}
}
回答by SM Chinna
import React from 'react';
import {connect} from 'react-redux';
import Userlist from './Userlist';
class Userdetails extends React.Component{
render(){
return(
<div>
<p>Name : <span>{this.props.user.name}</span></p>
<p>ID : <span>{this.props.user.id}</span></p>
<p>Working : <span>{this.props.user.Working}</span></p>
<p>Age : <span>{this.props.user.age}</span></p>
</div>
);
}
}
}
function mapStateToProps(state){
return {
user:state.activeUser
}
}
}
export default connect(mapStateToProps, null)(Userdetails);