了解React-Redux和mapStateToProps
我想了解react-redux的连接方法,以及它作为参数所需要的function。 特别是mapStateToProps
。
我理解它的方式, mapStateToProps
的返回值将是一个从状态派生的对象(因为它mapStateToProps
在存储中),其键将作为道具传递给目标组件(应用组件连接)。
这意味着您的目标组件所消耗的状态与存储在您的商店中的状态可能具有非常不同的结构。
这个可以吗? 这是预期的吗? 或者,这是你所谓的反模式?
是的,这是正确的。 它只是一个帮助函数,有一个简单的方法来访问你的状态属性
想象一下,你的应用程序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; }, {}) }
你得到了正确的第一部分:
是的mapStateToProps
的Store状态作为参数/参数(由react-redux::connect
),并用于链接组件与存储状态的某个部分。
通过链接我的意思是由mapStateToProps
返回的对象将作为道具在build设时提供,任何后续的更改将通过componentWillReceiveProps
可用。
如果你知道观察者devise模式,那么它就是这个或那个小的变化。
一个例子将有助于使事情更清楚:
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
处理显示并将filter状态保存到Redux Store状态,Demo组件正在“监听”或“订阅”到Redux Store状态filter,因此每当filter存储状态更改时(在filtersComponent
)react-redux检测到发生了变化,并通过将更改发送到componentWillReceiveProps来通知或“发布”所有监听/订阅的componentWillReceiveProps
,在这个示例中,将触发项目的重新filter并刷新显示,这是因为反应状态已经改变。
让我知道,如果这个例子是混乱或不够清楚,提供一个更好的解释。
至于: 这意味着你的目标组件所消耗的状态与存储在你的商店中的状态可以有很大不同的结构。
我没有得到这个问题,但只知道反应状态( this.setState
)与Redux Store状态完全不同!
反应状态用于处理反应组分的重绘和行为。 反应状态仅包含在组件中。
Redux Store状态是Redux reducers状态的组合,每个状态负责pipe理一小部分应用逻辑。 这些reducer属性可以通过任何组件的react-redux::connect@mapStateToProps
来获得! 这使得Redux存储状态可以访问应用程序,而组件状态本身是独占的。
React-Redux connect
用于更新每个操作的存储。
import { connect } from 'react-redux'; const AppContainer = connect( mapStateToProps, mapDispatchToProps )(App); export default AppContainer;
这个博客非常简单清楚的解释。
您可以克隆github项目或复制该博客中的代码以了解Redux连接。
好的
是的(如果你正在使用react-redux)
不是反模式。
它被称为“连接”你的组件或“如果聪明”。 这是devise。 它使您可以将组件从您的状态中解耦出来,从而增加代码的模块性。 它也允许你简化你的组件状态作为你的应用程序状态的一个子集,事实上,它可以帮助你遵守redux模式。 这样想一想:一个商店应该包含你的应用程序的整个文本。 对于大型应用程序,这可能包含数十个嵌套多层的属性。 你不想在每个电话上都收费(昂贵)。 如果没有mapStateToProps或者其他一些类似的东西,你就会想方设法地改变你的状态来改善性能/简化。
这个反应的例子是基于穆罕默德·梅洛基(Mohamed Mellouki)的例子。 但validation使用美化和linting规则 。 请注意,我们使用PropType来定义我们的道具和调度方法,以便我们的编译器不会尖叫。 这个例子还包括了一些在Mohamed例子中缺失的代码。 要使用连接,您需要从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);
此示例代码是组件的起始位置的良好模板。