Skip to content

Learn React From Beginner Perspective (Fetching Data)

Published: at 04:30 AM

this post will guide you through the fundamentals of React, popularity, pros & cons and especially how to fetching data in React common ways and new ways with React Router

Table of contents

Open Table of contents

What is React

React is the library (keep in your mind, REACT IS NOT FRAMEWORK because some people still thing react is framework) for web and native to help user build interfaces written in javascript. before learn react, you must have several fundamental like:

Popularity of React

according to data from Stack Overflow survey in below Statistic Survey

and from last year 2023 (june 2023, +90,000 developers): https://survey.stackoverflow.co/2023/

Pros & Cons Learn React

Pros:

Cons:

Fetching Data in React

in react, when we want fetching data from API, we can use hooks called useEffect. useEffect is a React Hook that lets you synchronize a component with an external system.

benefit using using useEffect:

you can see deeper what is useEffect, how to using it and etc in Web React. if you an Indonesian people, you can visit Web React Indonesian Version

let’s practice, first, we must install react. i recommended minimum install react using vite then Create React App. because Create React App from 2023 was deprecated. that means it was no longer maintained and using Create React App first install very slow than using react vite.

then, don’t forget install Node js. you can use Node js version minimal 20 or you can install NVM. if you user windows, you can use NVM Windows. why use nvm? for easily change node version.

after install node js, you can visit react vite web and you can install like this: install react vite for me, i will choose yarn create vite@latest folder-name --template react-ts because i love typescript LOL. but if you can only react, you can choose yarn create vite@latest folder-name --template react. don’t forget to yarn install or npm install or etc according what you use.

okay, let’s jump to main topic, i see in many tutorial for handling fetching data from API like this:

import { Fragment, useEffect, useState } from 'react';
import '../App.css'
import { Users, UsersResponse } from '../types/user.type';

function App() {
  const [data, setData] = useState<UsersResponse>({ users: [] });
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    setLoading(true);
    const getData = async (): Promise<void> => {
      try {
        const result = await fetch("https://jsonplaceholder.typicode.com/users");
        const resultData = await result.json();
        setLoading(false);
        setData(prevData => ({ ...prevData, users: resultData }));
      } catch (err: Error | unknown) {
        setError((err as Error).message);
      }
    }
    getData();
  }, []);

  if(loading) <div>loading ...</div>
  
  if(error) <div>ini message error {error}</div>

  return (
    <div>
      {data.users.map((val: Users, i: number) => (
        <Fragment key={i}>
          <div>name: {val.name}</div>
          <div>email: {val.email}</div>
        </Fragment>
      ))}
    </div>
  )

}

export default App;

in code above, its good and no problem. but, we can make simple using React Router like this:

import '../App.css'
import { useLoaderData } from 'react-router-dom'
import UserList from '@components/UserList';
import { UsersResponse } from '@types';

function App() {
  const data = useLoaderData() as UsersResponse;
  return (
    <UserList users={data.users} />
  )
}

export default App

so simple, right? how to achieve like that? there are some configuration:

main.tsx

import { StrictMode, Suspense } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import { RouterProvider } from 'react-router-dom'
import { router } from '@router'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <Suspense fallback={<div>loading...</div>}>
      <RouterProvider router={router} />
    </Suspense>
  </StrictMode>,
)

loader.tsx

import { LoaderFunction } from "react-router-dom";
import { Users, UsersResponse } from "@types";

export const loaderUsers: LoaderFunction = async (): Promise<UsersResponse> => {
  const result = await fetch("https://jsonplaceholder.typicode.com/users");
  if (result.status === 404) {
    throw new Response("not found", { status: 404 });
  }
  const resultData: Users[] = await result.json();
  return { users: resultData };
};

UserList.tsx

import { match, P } from "ts-pattern";
import { Fragment } from "react";
import { Users } from "@types";

interface UserListProps {
  users: Users[];
}
const UserList = ({ users }: UserListProps) => {
  const renderContent = match({ users })
    .with(
      { users: P.select(P.when((users) => Array.isArray(users))) },
      (users) => (
        <div>
          {users.map((val: Users, i: number) => (
            <Fragment key={i}>
              <div>name: {val.name}</div>
              <div>username: {val.username}</div>
            </Fragment>
          ))}
        </div>
      )
    )
    .otherwise(() => <div>data not found</div>);

  return renderContent;
};

export default UserList;

ErrorBoundary.tsx

import { isRouteErrorResponse, useRouteError } from "react-router-dom";
import { match, P } from "ts-pattern";

const ErrorBoundary = () => {
  const error = useRouteError();
  const renderContent = match({ error })
    .with(
      {
        error: P.when(
          (error) => isRouteErrorResponse(error) && error.status === 404
        ),
      },
      () => <div>url not found</div>
    )
    .with(
      {
        error: P.when(
          (error) => isRouteErrorResponse(error) && error.status === 401
        ),
      },
      () => <div>not Authorized</div>
    )
    .with(
      {
        error: P.when(
          (error) => isRouteErrorResponse(error) && error.status === 413
        ),
      },
      () => <div>Payload too large</div>
    )
    .otherwise(() => <div>error status not found</div>);

  return renderContent;
};

export default ErrorBoundary;

you will notice i import package from ts-pattern. why i choose ts-pattern? because i want data give to component more strictly.

i think that’s enought for now. you can see source code in React Vite Remix Style Github or contact me in my linkedin if you have a question.