理解React-Redux和mapStateToProps()

我试图理解react-redux的连接方法,以及它作为参数的函数。特别是mapStateToProps()

我理解它的方式,mapStateToProps的返回值将是一个从状态派生的对象(因为它存在于存储中),其键将作为道具传递给你的目标组件(组件连接被应用到)。

这意味着目标组件使用的状态可能与存储在存储库中的状态具有完全不同的结构。

Q:这样可以吗?< br > 问:这是预期的吗?< br > 问:这是反模式吗?< / p >

199421 次浏览

你第一部分答对了:

是的,mapStateToProps将Store状态作为参数/参数(由react-redux::connect提供),并用于将组件与Store状态的某些部分链接起来。

通过链接,我的意思是mapStateToProps返回的对象将在构造时作为道具提供,任何后续的更改都将通过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的react组件来处理显示并将过滤器状态持久化为Redux Store状态,演示组件是"监听"或“;subscribed"Redux存储状态过滤器,因此每当过滤器存储状态更改时(在filtersComponent的帮助下),react-redux检测到有更改并通知或“发布”;通过将更改发送到它们的componentWillReceiveProps,在本例中,这将触发项的重新筛选并刷新显示,因为react状态已更改。

如果这个例子令人困惑或不够清楚,请告诉我,以便提供更好的解释。

至于:这意味着目标组件使用的状态可能与存储在存储库中的状态具有完全不同的结构。

我没有得到问题,但只知道反应状态(this.setState)与Redux Store状态完全不同!

react状态用于处理react组件的重绘和行为。反应状态只包含在组件中。

Redux Store状态是Redux reducers状态的组合,每个状态负责管理一小部分应用程序逻辑。任何组件都可以在react-redux::connect@mapStateToProps的帮助下访问这些reducers属性!这使得Redux商店状态可访问的应用程序范围内,而组件状态是专属于自己。

是的,这是正确的。它只是一个帮助函数,有一个更简单的方法来访问你的状态属性

假设你的App state.posts中有一个posts

state.posts //
/*
{
currentPostId: "",
isFetching: false,
allPosts: {}
}
*/

和组件Posts

默认情况下,connect()(Posts)将为连接的组件提供所有状态道具

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>
)

更新actionCreators..

一个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;
}, {})
}

React-Redux connect用于更新每个操作的存储。

import { connect } from 'react-redux';


const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App);


export default AppContainer;

这是非常简单和清楚的解释在这个博客

你可以克隆github项目或复制粘贴从博客的代码来理解Redux连接。

This 反应 &回来的的例子是基于Mohamed Mellouki的例子。 但是使用美化产品毛羽规则进行验证。注意,我们定义了我们的道具 和调度方法使用proptype,这样我们的编译器就不会对我们大喊大叫。 这个例子还包含了Mohamed的例子中所缺少的一些代码行 的例子。要使用connect,你需要从react-redux导入它。这 例还结合的方法filterItems,这将防止范围的问题 组件。此源代码已使用JavaScript 美化自动格式化

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);

这个示例代码是一个很好的模板,可以作为组件的起点。

< p >问:Is this ok? < br > 是的< / p > < p >问:Is this expected? < br > 是的,这是预期的(如果你正在使用react-redux) < p >问:Is this an anti-pattern? < br > A:不,这不是反模式。

这被称为“连接”组件或“使其智能”。这是设计出来的。

它允许您在额外的时间内将组件与状态解耦,从而增加代码的模块化。它还允许您将组件状态简化为应用程序状态的子集,这实际上有助于您遵守Redux模式。

这样想:一个store应该包含应用程序的整个状态 对于大型应用程序,这可能包含数十个嵌套在多层深处的属性 你不希望每次通话都带着这些东西(很贵)。< / p >

如果没有mapStateToProps或类似的东西,你可能会被诱惑以另一种方式分割你的状态来提高性能/简化。

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);

下面是描述mapStateToProps行为的大纲/样板:

(这是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} />;
}
}

和明年

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} />;
}
}
}

我想对你提到的发言进行调整,即:

这意味着您的目标组件所消耗的状态可以 与存储时的状态有很大不同的结构 你的店铺< / p >

可以说,目标组件使用的状态有一小部分状态存储在redux存储区中。换句话说,组件使用的状态是redux存储区状态的子集。

就connect()方法的理解而言,它相当简单!Connect()方法可以向组件添加新道具,甚至覆盖现有道具。通过这个connect方法,我们也可以访问由Provider抛出给我们的redux存储的状态。两者的结合对您有利,您可以将redux存储的状态添加到组件的道具中。

上面是一些理论,我建议你看看这个视频,以更好地理解语法。

这是一个简单的概念。Redux从约简器中的操作创建一个无处不在的状态对象(存储)。像React组件一样,这个状态不需要显式地在任何地方编码,但它帮助开发人员在reducer文件中看到默认状态对象,以可视化正在发生的事情。在组件中导入减速机以访问该文件。然后mapStateToProps只选择其组件需要的存储中的键/值对。这就像Redux创建了一个React组件的全局版本

this.state = ({
cats = [],
dogs = []
})

不可能通过使用mapStateToProps()来改变状态的结构。您所做的只是选择组件需要的存储键/值对,并将值(从存储中的键/值列表中)传递给组件中的道具(本地键)。在列表中,每次只执行一个值。在此过程中不会发生结构更改。

附注:商店是本地的。reducer通常也将状态传递给数据库,与Action creator一起混合,但首先要理解这个简单的概念。

P.P.S.将每个减速器分离到单独的文件中,并且只导入组件需要的减速器,这是一个很好的做法。

是的,你可以做到。您甚至还可以处理状态并返回对象。

function mapStateToProps(state){
let completed = someFunction (state);
return {
completed : completed,
}
}
 

如果您想将与状态相关的逻辑从呈现函数转移到它的外部,这将非常有用。