lundi 19 novembre 2018

Data Fetching with Redux & Higher Order Components

I'm building a web application with React & Redux + Thunk middleware and am struggling to find the best pattern to connect my components with the data.

I have 3 different presentational components that all rely on the user profile object, which is fetched from the API and stored in Redux state. I have created a higher order function to wrap each of these components, providing them with the user profile object.

This higher order component is connected to Redux and uses selectors to get the data from the Redux store.

const withUser = WrappedComponent => {
    class WithUser extends Component {
        render = () => {
            const {loading, user} = this.props
            return <WrappedComponent user={user} loading={loading} {...this.props} />
        }
    }

    const loading = isLoading(['USER_GET'])
    const user = getCurrentUser()

    return connect(
        state => ({ loading: loading(state), user: user(state) }),
        {}
    )(WithUser)
}

export default withUser

Here is an example of one of my presentational components.

const Profile = props => {
    const {name, profileImage} = this.props.user
    return (
        <Wrapper>
            <Avatar src={profileImage} />
            <h2>{name}</h2>
        </Wrapper>
    )
}

export default withUser(Profile)

The crux of my question is: where is the optimal place to fetch the user data? Because I want these components to be entirely independent and context-agnostic, my first thought was to fetch the data using the componentDidMount lifecycle hook in the higher order component:

componentDidMount = () => {
    const {getUser, loading, user} = this.props
    if (!loading && !user) getUser()
}

The thought behind this is that if there's not already a user in the Redux state, and another component isn't already fetching it, then call getUser(). At first, this seemed to work perfectly, but problems arose when I load a page that initialises multiple components wrapped with withUser() simultaneously. getUser() sent off multiple requests to fetch the user data, before the loading reducer even picked up that the data was fetching, making !isLoading redundant.

Is there a better way to approach this situation? All help is appreciated.

Aucun commentaire:

Enregistrer un commentaire