Yola
Yola

Reputation: 19023

How to organize async fetching code in Reactjs

In many components, I need to fetch some data and I'm ending up with a lot of similar code. It looks like this:

const [data, setData] = useState();
const [fetchingState, setFetchingState] = useState(FetchingState.Idle);

useEffect(
    () => {
        loadDataFromServer(props.dataId);
    },
    [props.dataId]
);

async function loadDataFromServer(id) {
    let url = new URL(`${process.env.REACT_APP_API}/data/${id}`);
    let timeout = setTimeout(() => setFetchingState(FetchingState.Loading), 1000)
    try {
        const result = await axios.get(url);
        setData(result.data);
        setFetchingState(FetchingState.Idle);
    }
    catch (error) {
        setData();
        setFetchingState(FetchingState.Error);
    }
    clearTimeout(timeout);
}

How can I put it into a library and reuse it?

Upvotes: 0

Views: 615

Answers (2)

Yola
Yola

Reputation: 19023

Thank you guys for the suggestion, I came up with the following hook. Would be happy to some critics.

function useFetch(id, setData) {
    const [fetchingState, setFetchingState] = useState(FetchingState.Idle);
    
    useEffect(() => { loadDataFromServer(id); }, [id]);

    async function loadDataFromServer(id) {
        let url = new URL(`${process.env.REACT_APP_API}/data/${id}`);
        let timeout = setTimeout(() => setFetchingState(FetchingState.Loading), 1000)
        try {
            const result = await axios.get(url);
            setData(result.data);
            setFetchingState(FetchingState.Idle);
        }
        catch (error) {
            setData();
            setFetchingState(FetchingState.Error);
        }
        clearTimeout(timeout);
    }

    return fetchingState;
}

And this is how I use it:

function Thread(props) {
    const [question, setQuestion] = useState();

    const fetchingState = useFetch(props.questionId, setQuestion);

    if (fetchingState === FetchingState.Error) return <p>Error while getting the post.</p>;
    if (fetchingState === FetchingState.Loading) return <Spinner />;
    return <div>{JSON.stringify(question)}</div>;
}

Upvotes: 3

Maged Mohamed
Maged Mohamed

Reputation: 895

You can wrap your APIs calls in /services folder and use it anywhere

/services
  - Auth.js
  - Products.js
  - etc...

Example

Auth.js

import Axios from 'axios';

export const LoginFn = (formData) => Axios.post("/auth/login", formData);

export const SignupFn = (formData) => Axios.post("/auth/signup", formData);

export const GetProfileFn = () => Axios.get("/auth/profile")

in your component

import React, { useState } from 'react'
import { LoginFn } from '@Services/Auth'

export LoginPage = () => {
   const [isLoading, setIsLoading] = useState(false);

   const LoginHandler = (data) => {
     setIsLoading(true)
     LoginFn(data).then(({ data }) => {
       // do whatever you need
       setIsLoading(false)
    })
  }

  return (
    <form onSubmit={LoginHandler}>
     .......
  )
}

Upvotes: 2

Related Questions