Search code examples
reactjsfetchdry

How to fetch data in React blog app and stay DRY?


The question is simple. How to fetch data in your React blog and stay DRY? Let's say that you have just two components in your blog - PostsList and SinglePost, in both components you must fetch data, activate isLoading state, etc. There will be chunks of the same code in both components.

I investigated the situation a little bit, checking React-blog demo apps of big headless CMS providers, like Prismic or Sanity.io, and they all just repeat fetch functions in both PostsList and SinglePost.

Does anybody have any idea? You can point me to some good resources?


Solution

  • You can achieve this by using High Order Components. You can use them for reusing component logic. Let me show you an example of how to handle the isLoading with a HOC:

    HOC:

    import React, { useState } from 'react'
    
    const hocLoading = (WrappedComponent, loadingMessage) => {
     return props => {
        const [ loading, setLoading ] = useState(true) 
        const setLoadingState = isComponentLoading => {
            setLoading(isComponentLoading)
        }
        return(
            <>
                {loading && <p>{loadingMessage}</p>} //message showed when loading
                <WrappedComponent {...props} setLoading={setLoadingState} />
            </>
        )
     }
    }
    
    export default hocLoading
    

    As you can see this HOC is receiving the WrappedComponent and a message that you can set depending on your component. Then you will have to wrap every component where you want to show the loading feedback with the HOC and you can use the setLoading prop to stop showing the loading feedback:

    const Component = props =>  {
    const { setLoading } = props
    
    useEffect(() => {
     const loadUsers = async () => {
      await fetchData() // fetching data
      setLoading(false) // this function comes from the HOC to set loading false
     }
     loadUsers()
    },[ ])
    
     return (
      <div className="App">
        {usuarios.data.map(x => <p key={x.id}>{x.title}</p>)}
      </div>
     );
    }
    
    export default hocLoading(Component, "Data is loading") //component wrapped
     // with the HOC and setting feedback message
    

    This way you avoid repeating this process for every component. Regarding the data fetching you can create a Hook or a function that receives dynamic params so you can just call something like fetchData(url). Here is an example of a dynamic function for making request using axios:

    const baseUrl = "" //your BASE URL
    
    async function request(url,method,data){
    
     try {
        const response = await axios({
            method,
            url: `${baseUrl}${url}`,
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            },
            data: data ? data : undefined
        })
        return response
      } catch (e) {
        // handle error
      }
     }