The Simplest Way
Just do not use any libraries apart from the browser supported Fetch API.
Here is an example,
import { useEffect, useState } from 'react'; const ReactWay = () => { const [apiData, setApiData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); useEffect(() => { const fetchData = async () => { setIsLoading(true); const response = await fetch( 'https://jsonplaceholder.typicode.com/todos' ); const data = await response.json(); setApiData(data); setIsLoading(false); }; fetchData().catch((e) => setError(e.message)); }, []); return ( <div> <h1>React Way</h1> {error ? ( <>Oh no, there was an error</> ) : isLoading ? ( <>Loading...</> ) : apiData ? ( <> <ul> {apiData.map((item) => ( <li key={item.id}>{item.title}</li> ))} </ul> </> ) : null} </div> ); }; export default ReactWay;
This might be the way to do in a basic web app, but most of the times we are building something complex with various API calls. The above approach though simple is not the best way to handle data fetching logic in a complex app. The reason being it makes your component look bloated with logic and you having to write a lot of non-business logic. You could improve this by creating a custom hook and abstracting out the logic. Or the even better way is to use external libraries that provide much more than just fetching data like the ones below.
The Redux Way
If your project already uses Redux with the help of the Redux Toolkit, then you can use the RTK Query to handle this logic. It uses fetch internally, so you just need to set up endpoints and base URLs.
Here is how you set it up,
npm install @reduxjs/toolkit react-redux
Then in your project directory create a services folder with the API definition in it,
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const todoApi = createApi({ reducerPath: 'todoApi', baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/', }), endpoints: (builder) => ({ getTodos: builder.query({ query: () => 'todos', }), }), }); export const { useGetTodosQuery } = todoApi;
You can already see how you can set up all your endpoints at one place. Next all you have to do is set up your store. Do remember to export the auto-generated hooks as I did, this is how the RTK Query docs want you to do.
import { configureStore } from '@reduxjs/toolkit'; import { todoApi } from './services/todo'; export const store = configureStore({ reducer: { [todoApi.reducerPath]: todoApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(todoApi.middleware), });
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { store } from './store'; import App from './App'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
Finally in your component, call the query.
import { useGetTodosQuery } from '../services/todo'; const ReduxWay = () => { const { data, error, isLoading } = useGetTodosQuery(); return ( <div> <h1>Redux Way</h1> {error ? ( <>Oh no, there was an error</> ) : isLoading ? ( <>Loading...</> ) : data ? ( <> <ul> {data.map((item) => ( <li key={item.id}>{item.title}</li> ))} </ul> </> ) : null} </div> ); }; export default ReduxWay;
You could see how lean your component looks now.
The React Query Way
The simplest way of doing the complex stuff.
Here is how you set it up,
npm install react-query
and then set up your API’s in a similar way you did for Redux. Except less boilerplate code.y.js
Then your provide the query client to your component or even the entire app. Here, I wrapped it on the component itself.
import ReactQueryWay from './components/ReactQueryWay'; import { QueryClient, QueryClientProvider } from 'react-query'; const queryClient = new QueryClient(); const App = () => { return ( <> <QueryClientProvider client={queryClient}> <ReactQueryWay /> </QueryClientProvider> </> ); }; export default App;
Finally in your component you make the API call.
So, which is the best way?
It entirely depends on your team and project requirements, but React Query is the way to handle all the communication between your server and client. Though Redux also tries to do it with RTK Query add-on, React Query has far more features to offer as it was designed for this particular use case. It might be better to use RTK Query if your project already uses Redux, instead of adding an extra package to your project though community support on this aspect of Redux is still low when compared to React Query.
Read these below comparisons to make a better decision.
You can find the entire code with all three implementations on my GitHub.
WMK Tech Copyright © 2024. All rights reserved