0

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?

4
  • 5
    Probably use a custom hook? Commented Oct 25, 2020 at 18:48
  • 2
    Definitely custom hook. reactjs.org/docs/hooks-custom.html Commented Oct 25, 2020 at 18:55
  • 2
    SWR Is a very nice library with hooks for data fetching. It supports all kinds of loading scenarios, and it is very well tested. Commented Oct 25, 2020 at 19:50
  • @DavidGaloyan thank you, I saw this article, but I thought that maybe there is a good example already to avoid subtle bugs and to follow the best design technics. Commented Oct 26, 2020 at 0:01

2 Answers 2

3

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>;
}
Sign up to request clarification or add additional context in comments.

Comments

2

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}>
     .......
  )
}

1 Comment

This is not what I'm asking about. I'm asking about how to move the whole loadDataFromServer into some common place. Probably with fetchingState.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.