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:
- what is html
- what is css
- what is DOM
- what is ES6
- what is Node Js / Bun
- what is NPM
Popularity of React
according to data from Stack Overflow survey in below
and from last year 2023 (june 2023, +90,000 developers): https://survey.stackoverflow.co/2023/
- Popularity: React 40.58%, Angular 17.46%, Vue.js 16.38%, AngularJS 7.21%, Svelte 6.62%, Solid.js 1.36%, Lit 0.68%
- Desired: React 35.25%, Vue.js 17.42%, Svelte 14.18%, Angular 13.86%, Solid.js 4.93%, AngularJS 4.21%, Lit 0.92%
- Admired: Svelte 74.50%, Solid.js 71.71%, React 63.61%, Vue.js 57.87%, Lit 55.71%, Angular 50.75%, AngularJS 19.22%
Pros & Cons Learn React
Pros:
- Strong support Community
- there are many big company using react like Uber, Airbnb, Netflix, Pinterest, etc
- offer a well-supported library
Cons:
- learning curve learn react too high for beginner learning react because there is too many framework, library and folder structure from many developer
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
:
- Connecting to an external system
- Wrapping Effects in custom Hooks
- Controlling a non-React widget
- Fetching data with Effects and etc
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:
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.