user3591425
user3591425

Reputation:

How to curry a dispatch function with react/redux?

Summary: I am trying to pass a function down to a presentational component that will dispatch an action. The first argument (a key) must be defined in the container. A second argument (a page number) would be supplied in the presentational component. I'm suspecting I am doing something dumb.

I'm new to this so forgive me if my terminology is off or the example is poor. Here is what's going on:

const mapDispatchToProps = (dispatch) => ({
    changePage: bindActionCreators(changePosts, dispatch)
})

The purpose of this function is to change the page number of a certain group of posts in the store.

export const changePage = key => (dispatch, getState) => page => {
    return dispatch(onChangePage(key, page)); //changes the page of the key obj
}

What I was hoping to do was pass this down to a presentational component like so:

<Posts changePage={this.props.changePosts('news') />

Now inside the Posts component all I would have to do is

<a onClick={this.props.changePage(4)}>4</a>

to go to page 4. Essentially I'm telling the presentational component to change to page 4, but only where the key is 'news', which I defined a level up in the container.

This isn't working. The reason it isn't is because a 4 isn't being passed, but instead a Proxy Object:

[[Handler]]:Object
[[Target]]:SyntheticMouseEvent
[[IsRevoked]]:false

Am I misunderstanding how currying/dispatch works? I really appreciate any help.

Edit: more code

// container
class Index extends Component {
    static async getInitialProps({ store, isServer }) {
        await store.dispatch(fetchPosts('news'));
        return { ...store.getState() };
    }

    constructor(props) {
        super(props);
    }

    render() {
        const { nextPage, previousPage, changePage } = this.props;
        const { posts } = this.props.wordpress;
        const { news } = posts;
        return (
            <Main>
                <Posts
                    next={()=>nextPage('news')}
                    previous={()=>previousPage('news')}
                    changePosts={()=>changePage('news')}
                    items={news.items}
                />
            </Main>
        );
    }
}

const mapStateToProps = ({ wordpress }) => ({
    wordpress
})

const mapDispatchToProps = (dispatch) => ({
    fetchPosts: bindActionCreators(fetchPosts, dispatch),
    nextPage: bindActionCreators(nextPosts, dispatch),
    previousPage: bindActionCreators(previousPosts, dispatch),
    changePage: bindActionCreators(changePosts, dispatch)
})

export default withRedux(initStore, mapStateToProps, mapDispatchToProps)(Index);

// actions
export const changePage = key => (dispatch, getState) => page => {
    console.log(page) // this returns a proxy object for some reason
    return dispatch(changePage(key, page));
}

// The only real thing in the presentational component
<a onClick={props.changePosts(4)}>4</a>

Previous and Next buttons work

Upvotes: 1

Views: 1932

Answers (1)

Daniel Khoroshko
Daniel Khoroshko

Reputation: 2721

1) Firstly I should mention that mapDispatchToProps in your example looks a bit weird, because you only need to use bindActionCreators in case if you supply it with an object of actions. Most likely a simple object form of mapDispatchToProps would be enough in your case:

const mapDispatchToProps = {
    fetchPosts, 
    nextPage,
    previousPage,
    changePage,
};

2) Secondly the following piece of code is really confusing, why is it dispatching itself recursively?

// actions
export const changePage = key => (dispatch, getState) => page => {
    console.log(page) // this returns a proxy object for some reason
    return dispatch(changePage(key, page));
}

3) Finally, provided you already have an action creator changePage somewhere in you code that accepts args key and page, and it was added to mapDispatchToProps as I've mentioned earlier:

// in your container
<Posts
    ...
    changePosts={page => props.changePage('news', page)}
    ...
/>

// in your component
<a onClick={() => props.onClick(4)}>4</a>

Upvotes: 1

Related Questions