Steven Tchadenis
Steven Tchadenis

Reputation: 151

Redux pattern for getting state in action creator

I've identified 2 patterns for getting state in an action creator and am wondering which is better:

  1. Use redux-thunk and getState
  2. mapStateToProps in the component and pass the state back to Redux when calling an action creator

Example of each:

class SomeComponent {
    render() {
        return (
            <Button onPress={this.props.networkCall}/>
        )
    }
}

const mapDispatchToProps = {
    networkCall: actions.networkCall,
}

export default connect(undefined, mapDispatchToProps)(SomeComponent)

export networkCall() {
    return (dispatch, getState) => {
        const { dataForNetworkCall } = getState().someReducer
        dispatch(pending())
        axios.get(`something/${dataForNetworkCall}/something2`)
            .then(() => {
                dispatch(success())
            }
            ...
    }
}

OR


class SomeComponent {
    render() {
        const { networkCall, dataForNetworkCall } = this.props
        return (
            <Button onPress={networkCall(dataForNetworkCall)}/>
        )
    }
}

function mapStateToProps(state) {
    const { dataForNetworkCall } = state.someReducer
    return { dataForNetworkCall }
}

const mapDispatchToProps = {
    networkCall: actions.networkCall,
}

export default connect(mapStateToProps, mapDispatchToProps)(SomeComponent)

export networkCall(dataForNetworkCall) {
    return (dispatch) => {
        dispatch(pending())
        axios.get(`something/${dataForNetworkCall}/something2`)
            .then(() => {
                dispatch(success())
            }
            ...
    }
}

I feel like 2 is a bad idea because it involves passing state to the Component just to pass it back to Redux. However, there seems to be a lot of articles online saying option 1 is an anti-pattern (including Dan Abramov himself saying it is an anti-pattern). So, what is the "best" way?

Upvotes: 3

Views: 510

Answers (1)

Tomasz Mularczyk
Tomasz Mularczyk

Reputation: 36209

I always follow the latter example, meaning that my action creators are not dependent on a store. However, there was a case when I had to pass user token to almost every action that required interaction with server API. Instead of repeatedly pass it to every action creator or accessing it within with getState() I wrote a custom middleware (not that difficult) that would recognize these actions and enrich them with another prop called userToken.

Back to the Dan Abramov answer. He says in a comment:

It’s fine to read from the store in the action creator.

which is confusing to me, but I think what he meant is that is fine to do it for certain reasons:

I think it’s acceptable is for checking cached data before you make a request, or for checking whether you are authenticated (in other words, doing a conditional dispatch)

... and that using getState may result in a situation where:

... it is hard to trace where those incorrect values come from because they are already part of the action, rather than directly computed by a reducer in response to an action.

What I think he means is that action creators should not pass updated parts of the store that get replaced by the reducer, but action should describe what is happening and the reducers should handle the update:

Not:

here is the new item list - replace it in the store

But:

we need to remove the item with id: 5 - handle it

...which is a bit different scenario than accessing a value from store to use it in a request. I advice you to read the linked blog. It answers in deep your question and there are some arguments with examples about whats best. TL;DR - it's a debate which approach is better.

Upvotes: 2

Related Questions