How to fetch data each time user opens the screen and update the state only if the fetched data is different than the current data in state

Viewed 2678

I am relatively new to react, react native and redux and I have one question about fetching the data from the api and updating the state.

What I want to do is: - each time a user opens the screen (i.e Posts) I want to fetch data from the api and update the state.

So that: - I always have newly fetched data in the state and rendered on the screen.

If I fetch the data only in componentDidMount lifecycle method then I won't always have fresh data.

Example: There are two screens Post and Posts. If a user opens posts screen for the first time then componentDidMount is triggered and posts are fetched and rendered. Then he goes to Post screen adds a new post and goes back to Posts screen then he will not see that new post because the posts will be displayed from the state fetched in componentDidMount method.

What is the best way to handle this and always have latest data?

class Posts extends Component {
    componentDidMount() {
        this.props.fetchPosts();
    }

    componentDidUpdate(prevProps) {
        this.props.fetchPosts();
    }

    render () { ... }
}

const mapStateToProps = state => {
    return {
        posts: state.posts.posts,
        loading: state.posts.loading,
    }
}

const mapDispatchToProps = dispatch => {
     return {
         fetchPosts: () => dispatch(actions.fetchPosts()),
     }
}

export default connect(mapStateToProps, mapDispatchToProps)(Posts)

Action

export const fetchPosts = () => {
    return dispatch => {

         dispatch(fetchStarted());

         apiFetchPosts()
         .then(({data}) => {

             const posts = data.data;

             dispatch(fetched(posts))
         })
         .catch(error => {
             dispatch(fetchFailed(error));
         })
     }
 }

 const fetchStarted = () => {
      return {
         type: actionTypes.POSTS_FETCH_START,
      }
 }

 const fetched = (posts) => {
      return {
           type: actionTypes.POSTS_FETCH_SUCCESS,
           posts,
      }
 }

 const fetchFailed = (error) => {
     return {
         type: actionTypes.POSTS_FETCH_FAILED,
     }
 }
2 Answers

Update as you go

In your case, you should be sending a POST request to insert a new post. That request should have the newly created post as a response. You should use that response to update the list of posts you have in the redux state. Simply add the new post to the list.

The same goes for removing posts, once you send a DELETE request, you should also remove that post from the state.

Add timed cache

If you want to refetch the posts when you haven't fetched it for a while, you should implement some kind of caching solution:

When you fetch the posts for the first time you can also store the timestamp of the request. When the user visits the Posts page, you can check if the timestamp is too old e.g. 5 minutes in the past, and refetch it accordingly.

Refetch everytime

If you want to simply refetch the posts every time the user visits that page, you can use the useEffect hook or a combination of componentDidMount and componentDidUpdate.

Please note:

You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you’ll cause an infinite loop. Source

You could use componentDidUpdate

Related