Understanding React-Redux and mapStateToProps() Understanding React-Redux and mapStateToProps() reactjs reactjs

Understanding React-Redux and mapStateToProps()


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

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

And component Posts

By default connect()(Posts) will make all state props available for the connected Component

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

const Posts = ({isFetching, allPosts}) => (  <div>    {/* access isFetching, allPosts directly */}  </div> )connect(  state => state.posts)(Posts)

mapDispatchToProps

normally you have to write dispatch(anActionCreator())

with bindActionCreators you can do it also more easily like

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

An example of an 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:

const bindActionCreators = (actions, dispatch) => {  return Object.keys(actions).reduce(actionsMap, actionNameInProps => {    actionsMap[actionNameInProps] = (...args) => dispatch(actions[actionNameInProps].call(null, ...args))    return actionsMap;  }, {})}


Q: Is this ok?
A: yes

Q: Is this expected?
Yes, this is expected (if you are using react-redux).

Q: Is this an anti-pattern?
A: No, this is not an anti-pattern.

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.

Think about it this way: a store is supposed to contain the entire state 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.


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.

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.

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.

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!

The react state is used to handle the redraw and behavior of the react component. The react state is contained to the component exclusively.

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.