Skip to content

Props lost if mapStateToProps & mapDispatchToProps reference same high level prop #324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bcardi opened this issue Mar 17, 2016 · 1 comment

Comments

@bcardi
Copy link

bcardi commented Mar 17, 2016

I was hoping to group my redux state and dispatch props under a single property in my component, but my state props are lost when redux completes its merge.

const mapStateToProps = (state,ownProps) => {
    return {
        redux: {
            state: {
                login: loginStateSelector(state)
            }
        }
    };
};

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        redux: {
            actions: {
                loginUser: (creds) => {
                    dispatch(UserActions.loginUser(creds))
                },
                showModal: (modalName) => {
                    dispatch(UserActions.showModal(modalName))
                }
            }
        }
    };
};

I expected to see this

props: {
    redux: {
        state: {
            login: loginStateSelector(state)
        },
        actions: {
            loginUser: (creds) => {
                dispatch(UserActions.loginUser(creds))
            },
            showModal: (modalName) => {
                dispatch(UserActions.showModal(modalName))
            }
        }
    }
}

But, after redux combines the props, i see this

props: {
    redux: {
        actions: {
            loginUser: (creds) => {
                dispatch(UserActions.loginUser(creds))
            },
            showModal: (modalName) => {
                dispatch(UserActions.showModal(modalName))
            }
        }
    }
}

Is this a bug or working as designed? it seems that redux should be able to combine the two without loss of data.

@gaearon
Copy link
Contributor

gaearon commented Mar 21, 2016

React Redux can’t guess how to merge two completely different objects. It isn’t obvious: for example, if both were Immutable maps, “merging” them naïvely would break them completely.

We let you specify a third argument called mergeProps to compare the merging behavior. By default it uses Object.assign()-like behavior which is why props are overridden. But you can specify a different behavior:

const mapStateToProps = (state,ownProps) => {
    return {
        login: loginStateSelector(state)
    };
};

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        loginUser: (creds) => {
            dispatch(UserActions.loginUser(creds))
        },
        showModal: (modalName) => {
            dispatch(UserActions.showModal(modalName))
        }
    };
};

const mergeProps = (stateProps, dispatchProps, ownProps) => {
    return {
        ...ownProps,
        redux: { 
            state: stateProps, 
            actions: dispatchProps
        }
    };
};

export default connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps
);

I am using object spread operator in this example but you can write it with Object.assign() instead (don’t forget to add a polyfill for it in this case):

const mergeProps = (stateProps, dispatchProps, ownProps) => {
    return Object.assign({}, ownProps, {
        redux: {
            state: stateProps,
            actions: dispatchProps
        }
    });
};

I hope this helps!

Note that grouping objects like this will cause unnecessary allocations and will also make performance optimizations harder because we can no longer rely on shallow equality of result props as a way to tell whether they changed. So you will see more renders than with a simple approach without namespacing which we recommend in the docs.

@gaearon gaearon closed this as completed Mar 21, 2016
foiseworth pushed a commit to foiseworth/react-redux that referenced this issue Jul 30, 2016
Fix `bindActionCreators` example
@reduxjs reduxjs deleted a comment from hai98th Mar 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants