1
votes

(This is maybe not a redux question per sé)

My current strategy/thoughtprocess is this: every container component that needs data, dispatches an action that fetches that data in componentDidMount (which then triggers an api request, that dispatches an action that updates the store)

The problem with this: some components are fetching the exact same data. This also means that when I load my app a (sometimes "large") number of unneccessary requests and rerenders happen.

My question: what's a better way of handling this?

Personally I see two ways:

  • somehow cache the data returned from the server, and if a new request is triggered that has cached data (and happens within a certain timeout), return that cached data instead of making a new request.
  • fetch all my app data somewhere else in one spot. (the drawback I see is that my container components aren't "self-sufficient" then)

My guess is that there is some better way that I can't seem to see :)

2

2 Answers

1
votes

To improve the initial render, I would:

  • fetch the data on the server and populate redux store
  • do server rendering and pass the redux store state to client
  • add a check to your componentDidMount to see if the data is available

Something like

componentDidMount() {
  if (this.props.shouldFetchData) {
    this.props.fetchData()
  }
}

We have a system like this in place and it works fine. The only big downside is that you have to do the api call in 2 different places ( client and server ), but I've yet to see a solution with server side rendering that doesn't have that duplication.

0
votes

I like to use redux-thunk for this type of thing as you can get access to the state and make decisions accordingly. e.g.

const fetchData = (id) => {
    return (dispatch, getState) =>  {
        if (getState().path.to.data.isLoading)
            return

        dispatch({type: 'LOADING_DATA'})

        fetch(`${url}/${id}`).then(data => dispatch({type: 'SET_DATA', data}))
    }
}

Then in your reducer, you set isLoading true when the 'LOADING_DATA' action is dispatched and then toggle it back to false when the 'SET_DATA' is received. e.g.

const initialState = {isLoading: false}

const reducer = (state = initialState, action) => {
    switch(action.type) {
        case 'LOADING_DATA':
            return { ...state, isLoading: true }
        case 'SET_DATA':
            return { ...state, ...data, isLoading: false }
    }
}

All components looking for the same data in the store will be rerendered when the store is updated.

You can also extend this pattern as much as you like to suit your need, for example, store a timestamp instead of a boolean and don't follow through on the request for a certain timeout.