Sep 14, 2026
/
By Ariffud M.
/
28 min Read
This React tutorial teaches you really to group up a React app, constitute JSX, build components, walk props, negociate state, usage hooks, grip forms, adhd routes, fetch API data, and build a mini moving project.
It useful for illustration a beginner React course, pinch applicable lessons, examples, and exercises built astir a task locator app you’ll complete by the end.
Here’s the learning way successful this React tutorial:
- Prepare a React task pinch Vite, Node.js, and npm.
- Learn JSX, build React components, and walk information pinch props.
- Add interactive state, events, and controlled forms.
- Use hooks for illustration useState and useEffect to negociate logic.
- Add React Router and fetch API data.
- Build a elemental React task locator project.
What will you study successful this React tutorial?
You’ll study React from task setup to an app that’s fresh to people online, pinch examples and short exercises that thief you use each conception arsenic you go.
The lessons usage the aforesaid task locator arsenic a moving project, truthful you tin spot really individual React features activity together successful a complete app.
The array beneath shows what you’ll believe successful each instruction and really it contributes to the last project:
| Lesson | Concept | Practice task | Project outcome |
| 1 | Node.js, npm, and Vite | Start the improvement server | React task moving locally |
| 2 | JSX and rendering | Update the page markup | First civilization interface |
| 3 | Components and props | Build reusable task items | Structured task list |
| 4 | State and events | Toggle and delete tasks | Interactive task tracker |
| 5 | Forms | Validate and adhd tasks | User-created tasks |
| 6 | Hooks | Run an effect and create a civilization hook | Reusable constituent logic |
| 7 | React Router | Add aggregate page views | Navigation betwixt views |
| 8 | API data | Adapt fetched information and grip petition states | External task information pinch loading and correction feedback |
| 9 | Final project | Test and build the app for production | Complete task locator fresh to deploy |
React tutorial prerequisites
The prerequisites for pursuing this React tutorial are basal knowledge of HTML, CSS, JavaScript, and moving commands successful a terminal. We’ll show you really to instal Node.js and npm, truthful you don’t request them beforehand.
You tin travel on moreover if you’ve ne'er utilized React before.
JavaScript is the astir important prerequisite because you’ll usage it erstwhile moving pinch React to create components, grip events, update state, and activity pinch data.
You should beryllium acquainted pinch JavaScript variables, functions, arrays, objects, destructuring, modules, and array methods specified arsenic map() and filter().
What app will you build successful this React tutorial?
You’ll build a React task locator that lets you add, complete, reopen, and delete tasks, past unfastened individual task specifications and navigate betwixt pages.
The vanished app will besides load starter tasks from an API, show loading and correction feedback, and see a responsive layout that useful connected smaller screens. By the end, you’ll person a complete accumulation build that’s fresh to deploy.
How do you group up a React project?
You group up the React task by installing Node.js and npm, past utilizing Vite to create and tally the app.
The pursuing sections locomotion you done installing the required tools, creating the React project, and knowing its main files.
Check our Node.js tutorial if you want to study much astir Node.js aliases request a refresher connected the basics.
Install Node.js and npm
To instal Node.js and npm, download the latest Long-Term Support (LTS) type of Node.js from its charismatic website. Then, double-click the installer to instal it connected your computer. npm comes pinch Node.js, truthful you don’t request to instal it separately.
You request Node.js to tally devices for illustration Vite, while npm installs and manages the packages your React task uses.
After installation, unfastened your terminal and cheque that some devices are available:
node --version npm --versionEach bid should return a type number. Reinstall Node.js if either bid doesn’t return one.

Create a React app pinch Vite
Create the task locator app pinch Vite by moving the task setup command, installing its packages, and starting the section improvement server.
This tutorial uses Vite because Create React App, a instrumentality antecedently utilized to commencement React projects, is deprecated. Vite gives you a ready-to-use React project, truthful you tin commencement coding without configuring the setup yourself.
Run the pursuing commands successful your terminal:
npm create vite@latest react-task-tracker -- --template react cd react-task-tracker npm install npm tally devThe –template react action creates a JavaScript React project, while npm install installs the packages listed successful package.json. Then, npm tally dev starts the improvement server.
Vite will show a section reside successful your terminal, specified as http://localhost:5173. Open it successful your browser to spot the starter React app.

Understand the React task files
The main React task files you’ll activity pinch are wrong the src folder, including main.jsx, App.jsx, and the project’s CSS files. As you build the task tracker, you’ll besides create folders for components and pages.
Here’s what you’ll usage each important record aliases files for:
| File aliases folder | What you usage it for |
| package.json | Lists the task packages and commands, specified arsenic npm tally dev |
| index.html | Provides the HTML page wherever your React app appears |
| src/main.jsx | Starts the React app and displays the main App component |
| src/App.jsx | Contains the main app constituent and, later, its routes |
| src/App.css | Stores styles for the main app |
| src/index.css | Stores world styles for the app |
| src/components | Stores reusable components you’ll create, specified arsenic Header.jsx and TaskItem.jsx |
| src/pages | Stores the page components you’ll create for React Router |
Match filename capitalization exactly, specified arsenic App.jsx and TaskItem.jsx, because immoderate operating systems dainty uppercase and lowercase filenames differently.
How does React render a personification interface?
React renders a personification interface by moving your components, utilizing the JSX they return to find what should appear, and updating the page successful your browser pinch the result.
This process has 3 main steps:
- Trigger. The first render starts erstwhile React runs createRoot(…).render() successful src/main.jsx. Later, changes to authorities tin trigger different render.
- Render. React runs your components and sounds their JSX to find what the interface should look like.
- Commit. React applies the basal changes to the page truthful you spot the latest interface.
For example, changing a task’s position triggers different render. React calculates the latest interface, past commits the basal changes to the page.
What is JSX successful React?
JSX is simply a JavaScript syntax hold that lets you constitute HTML-like markup wrong React components. You usage it to picture what should look connected the page while keeping that markup adjacent to the JavaScript that controls it.
JSX looks akin to HTML, but it follows a fewer different rules:
- Wrap aggregate elements successful 1 genitor constituent aliases a part specified arsenic <>…</>.
- Close each tag, including self-closing tags specified arsenic <img />.
- Use className alternatively of the HTML class attribute.
- Write astir attributes successful camelCase, specified arsenic onClick.
- Put JavaScript values aliases expressions wrong curly braces, specified arsenic {taskName}.
For example, switch the contents of src/App.jsx with:
const taskName = 'Learn JSX'; function App() { return ( <main className="task-list"> <h1>Task tracker</h1> <p>{taskName}</p> </main> ); } export default App;Here, the JSX defines the heading and paragraph that look successful your browser. The {taskName} look inserts the worth assigned to the taskName adaptable into the paragraph.
For a speedy exercise, alteration ‘Learn JSX’ to different task. Then, wrong the <main> element, adhd different paragraph beneath <p>{taskName}</p>, specified arsenic <p>Not started</p>.
Save App.jsx, past cheque that the updated task and the caller position look successful your browser.

How do you render your first React component?
You render your first React constituent by importing App.jsx into src/main.jsx and passing <App /> to render(). The Vite task you created earlier already includes this setup.
Open src/main.jsx to spot really it works:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App.jsx'; createRoot(document.getElementById('root')).render( <StrictMode> <App /> </StrictMode>, );The document.getElementById(‘root’) portion finds the constituent pinch the root ID successful index.html. React past displays the app wrong that element, which is why the JSX you added to App.jsx appears successful your browser.
You’ll adhd much components wrong App arsenic you build the task tracker. StrictMode besides helps you drawback communal problems while developing, and its other checks don’t tally successful production.
How does React update the DOM?
React updates the Document Object Model (DOM) during the perpetrate measurement by applying the changes needed to make the page lucifer the latest render.
The DOM represents the elements presently displayed successful your browser. React tin update a changed constituent without recreating unrelated parts of the page.
For example, erstwhile a task changes from Open to Done, React tin update the task’s displayed position while leaving unchanged elements, specified arsenic the page heading, alone.
How do React components work?
React components activity arsenic reusable JavaScript functions that return JSX for portion of the interface. Each 1 handles 1 part, specified arsenic a header, task list, aliases individual task, past combines pinch different components to build the afloat page.
Keeping these parts abstracted makes your React task easier to update.
Create your first React component
Create your first React constituent by defining a JavaScript usability pinch a capitalized sanction and returning JSX from it. You’ll commencement pinch the task locator header.
First, create the src/components folder. Inside it, create Header.jsx:
function Header() { return ( <header className="header"> <h1>Task tracker</h1> </header> ); } export default Header;The export default Header statement lets you import the constituent into different file.
Next, switch the contents of src/App.jsx with:
import Header from './components/Header.jsx'; function App() { return ( <main className="app"> <Header /> </main> ); } export default App;Add <Header /> wrong App to show the header successful the page. Save some files, and you should spot Task tracker successful your browser.
Pass information pinch props
To walk information pinch props, adhd values to a kid constituent erstwhile you render it, past publication those values wrong the child.
Create src/components/TaskItem.jsx:
function TaskItem({ title, done }) { return ( <li className="task-item"> {done ? '✓ ' : '○ '} {title} </li> ); } export default TaskItem;The { title, done } syntax sounds the title and done props passed to the component.
Now import TaskItem into src/App.jsx and render it twice:
import Header from './components/Header.jsx'; import TaskItem from './components/TaskItem.jsx'; function App() { return ( <main className="app"> <Header /> <ul> <TaskItem title="Learn JSX" done={true} /> <TaskItem title="Build a component" done={false} /> </ul> </main> ); } export default App;The first TaskItem appears complete, while the 2nd appears incomplete because they person different done values.

Note that props are read-only. A kid constituent tin usage the values it receives, but it should ne'er alteration them. Only the genitor passing the prop tin alteration it.
Compose components into a page
Compose components into a page by creating a TaskList component, nesting it wrong App, and rendering a TaskItem for each task successful the list.
Create src/components/TaskList.jsx:
import TaskItem from './TaskItem.jsx'; function TaskList({ tasks }) { if (tasks.length === 0) { return <p>No tasks yet.</p>; } return ( <ul className="task-list"> {tasks.map((task) => ( <TaskItem key={task.id} title={task.title} done={task.done} /> ))} </ul> ); } export default TaskList;The map() method creates 1 TaskItem for each task successful the array. The key gives React a unchangeable measurement to place each task erstwhile the database changes.
Next, update src/App.jsx:
import Header from './components/Header.jsx'; import TaskList from './components/TaskList.jsx'; const tasks = [ { id: 1, title: 'Learn JSX', done: existent }, { id: 2, title: 'Build a component', done: mendacious }, ]; function App() { return ( <> <Header /> <main className="app"> <TaskList tasks={tasks} /> </main> </> ); } export default App;This building keeps the task-list markup retired of App.jsx and gives each portion of the interface a clear responsibility.
How do authorities and events make a React app interactive?
State and events make a React app interactive by storing information that tin alteration (state) and responding to actions specified arsenic clicks (events). For the task locator app, you’ll usage authorities to shop the tasks and click events to people them complete aliases delete them.
React updates the page to show the caller information erstwhile you interact pinch a task and its authorities changes.
Add authorities pinch useState
Add authorities pinch useState by calling it wrong your constituent and passing the starting value. useState gives you the existent worth and a usability for updating it. Use it erstwhile your constituent needs to retrieve information that tin change.
In src/App.jsx, import useState and move the task information into state:
import { useState } from 'react'; import Header from './components/Header.jsx'; import TaskList from './components/TaskList.jsx'; const initialTasks = [ { id: 1, title: 'Learn JSX', done: existent }, { id: 2, title: 'Build a component', done: mendacious }, ]; function App() { const [tasks, setTasks] = useState(initialTasks); return ( <> <Header /> <main className="app"> <TaskList tasks={tasks} /> </main> </> ); } export default App;In const [tasks, setTasks] = useState(initialTasks), tasks contains the existent task list, while setTasks updates it. initialTasks provides the starting worth erstwhile the constituent first renders.
For practice, temporarily alteration useState(initialTasks) to useState([]). The task database should show No tasks yet. Change it backmost to useState(initialTasks) earlier continuing.
Handle click events
To grip click events, walk functions to the onClick props successful TaskItem and link them to the task authorities successful App.
First, adhd these functions beneath the useState statement successful App.jsx:
function toggleTask(id) { setTasks((currentTasks) => currentTasks.map((task) => task.id === id ? { ...task, done: !task.done } : task ) ); } function deleteTask(id) { setTasks((currentTasks) => currentTasks.filter((task) => task.id !== id) ); }Then, walk some functions to TaskList:
<TaskList tasks={tasks} onToggle={toggleTask} onDelete={deleteTask} />Next, update src/components/TaskList.jsx, truthful it passes the functions and each task ID to TaskItem:
import TaskItem from './TaskItem.jsx'; function TaskList({ tasks, onToggle, onDelete }) { if (tasks.length === 0) { return <p>No tasks yet.</p>; } return ( <ul className="task-list"> {tasks.map((task) => ( <TaskItem key={task.id} id={task.id} title={task.title} done={task.done} onToggle={onToggle} onDelete={onDelete} /> ))} </ul> ); } export default TaskList;Finally, update src/components/TaskItem.jsx:
function TaskItem({ id, title, done, onToggle, onDelete, }) { return ( <li className="task-item"> <span> {done ? '✓ ' : '○ '} {title} </span> <button type="button" onClick={() => onToggle(id)} > {done ? 'Mark open' : 'Mark done'} </button> <button type="button" onClick={() => onDelete(id)} > Delete </button> </li> ); } export default TaskItem;Click Mark done aliases Mark open to alteration a task’s status. Click Delete to region it from the list.

The arrow usability successful onClick={() => onToggle(id)} waits until you click the fastener earlier calling onToggle. Writing onClick={onToggle(id)} alternatively would telephone the usability instantly while React renders the component.
For a speedy test, temporarily adhd a Log task fastener wrong the <li className=”task-item”> constituent successful TaskItem.jsx and springiness it onClick={() => console.log(title)}.
Click the fastener and corroborate that the task title appears successful your browser’s developer console. Then, region the fastener earlier continuing.
Update arrays and objects without mutation
Update arrays and objects successful React authorities by creating caller versions alternatively of changing the existing authorities directly. The toggleTask and deleteTask functions you conscionable added some travel this pattern.
In toggleTask, map() creates a caller array. For the task pinch the matching ID, the dispersed syntax copies the existing task into a caller entity and changes its done value:
currentTasks.map((task) => task.id === id ? { ...task, done: !task.done } : task )The different task objects enactment unchanged.
In deleteTask, filter() creates a caller array without the task whose ID matches the 1 you want to remove:
currentTasks.filter((task) => task.id !== id)Avoid changing authorities directly, for example:
task.done = true;Instead, create a caller entity pinch the updated value:
{ ...task, done: existent }The aforesaid norm applies to arrays. Instead of methods specified arsenic push(), create a caller array and walk it to setTasks.
How do React forms cod personification input?
React forms cod personification input by storing section values successful authorities and updating them arsenic you type. In the task tracker, TaskForm will power the title section and walk submitted values to App.
Build a controlled form
You tin build a controlled shape by mounting the input worth from React authorities and updating that authorities whenever you type.
Create src/components/TaskForm.jsx:
import { useState } from 'react'; function TaskForm({ onAdd }) { const [title, setTitle] = useState(''); usability handleSubmit(event) { event.preventDefault(); onAdd(title); setTitle(''); } return ( <form className="task-form" onSubmit={handleSubmit}> <label htmlFor="task-title"> Task name </label> <input id="task-title" name="task-title" type="text" placeholder="Add a caller task..." value={title} onChange={(event) => setTitle(event.target.value)} /> <button type="submit"> Add task </button> </form> ); } export default TaskForm;The value={title} prop keeps the section worth connected to title state, while onChange updates that authorities arsenic you type.
When you taxable the form, handleSubmit prevents the browser’s default page reload, passes the existent title to onAdd, and clears the field.
Validate input earlier updating state
Validate the task title earlier calling onAdd truthful quiet aliases whitespace-only values don’t go tasks.
In TaskForm.jsx, switch handleSubmit with:
function handleSubmit(event) { event.preventDefault(); const trimmedTitle = title.trim(); if (trimmedTitle === '') { return; } onAdd(trimmedTitle); setTitle(''); }The trim() method removes spaces from the opening and extremity of the title. A worth containing only spaces becomes an quiet string, truthful the usability stops earlier passing it to onAdd.
This validation is capable for the task tracker. You tin adhd different rules, specified arsenic a maximum title length, erstwhile your task needs them.
Add caller tasks to the project
To adhd caller tasks to your project, link TaskForm to the tasks authorities successful App.jsx.
First, import TaskForm astatine the apical of src/App.jsx:
import TaskForm from './components/TaskForm.jsx';Then, adhd this usability wrong App, beneath your existing useState line:
function addTask(title) { const newTask = { id: Date.now(), title, done: false, }; setTasks((currentTasks) => [ ...currentTasks, newTask, ]); }Finally, render TaskForm supra TaskList and walk addTask done the onAdd prop:
<TaskForm onAdd={addTask} /> <TaskList tasks={tasks} onToggle={toggleTask} onDelete={deleteTask} />When you taxable a valid title, addTask creates a caller task pinch an ID and an first done worth of false, past adds it to the task list.

How do React hooks negociate logic and broadside effects?
React hooks negociate constituent logic by letting you shop changing data, link to outer systems, and reuse logic crossed components.
You’ve already utilized useState for task information and shape values. Next, you’ll usage useEffect to tally codification that connects your constituent to thing extracurricular React, specified arsenic an API.
React besides provides different hooks, including useRef, useMemo, and useCallback, but you don’t request them for this task locator yet.
Use useEffect to fetch data
To usage useEffect to fetch data, commencement the petition wrong the effect and shop the consequence successful state.
Create src/components/ApiTasks.jsx:
import { useEffect, useState } from 'react'; function ApiTasks() { const [tasks, setTasks] = useState([]); useEffect(() => { fto disregard = false; async usability loadTasks() { effort { const consequence = await fetch( 'https://jsonplaceholder.typicode.com/todos?_limit=5' ); if (!response.ok) { propulsion caller Error( `Request grounded pinch position ${response.status}` ); } const information = await response.json(); if (!ignore) { setTasks(data); } } drawback (error) { if (!ignore) { console.error(error); } } } loadTasks(); return () => { disregard = true; }; }, []); return ( <ul> {tasks.map((task) => ( <li key={task.id}> {task.completed ? '✓ ' : '○ '} {task.title} </li> ))} </ul> ); } export default ApiTasks;This illustration requests 5 sample tasks from JSONPlaceholder aft the constituent renders. When the petition succeeds, setTasks stores the consequence and triggers different render pinch the task data.
The quiet dependency array successful useEffect(…, []) intends the effect runs erstwhile aft the constituent first appears, alternatively of aft each render. With StrictMode enabled, React runs the effect doubly during improvement to thief you spot missing cleanup.
This doesn’t hap successful production, truthful 2 requests successful your web tab are expected.
The ignore adaptable prevents the petition from updating authorities aft React cleans up the effect.
To cheque the result, temporarily import ApiTasks into src/App.jsx and render <ApiTasks /> beneath TaskList. Five sample tasks should look aft the petition completes.

Remove the impermanent <ApiTasks /> render and its import aft confirming the result.
Avoid communal useEffect mistakes
Avoid communal useEffect mistakes by reserving effects for codification that needs to synchronize pinch thing extracurricular React, not values you tin cipher during rendering aliases actions you tin grip directly.
For example, cipher the number of completed tasks straight from tasks:
const completedTasks = tasks.filter( (task) => task.done );React recalculates completedTasks erstwhile the constituent renders, truthful you don’t request an effect to shop the consequence separately.
Keep user-triggered logic successful arena handlers arsenic well. For example, adhd a task successful the shape submission handler and delete a task successful its click handler, alternatively than utilizing an effect.
Also cheque an effect’s limitations erstwhile it updates state. Updating a worth that causes the aforesaid effect to tally again tin create an update loop.
Create a civilization hook
You tin create a civilization hook by moving reusable logic that uses authorities aliases different hooks into a JavaScript usability whose sanction starts pinch use. The usability tin telephone different React hooks and return the values aliases functions your components need.
For example, create src/hooks/useTaskFilter.js to support the task-filtering logic successful 1 place:
import { useState } from 'react'; function useTaskFilter(tasks) { const [filter, setFilter] = useState('all'); const filteredTasks = tasks.filter((task) => { if (filter === 'done') { return task.done; } if (filter === 'active') { return !task.done; } return true; }); return { filter, setFilter, filteredTasks, }; } export default useTaskFilter;A constituent tin past telephone useTaskFilter(tasks) to get the existent filter, alteration it pinch setFilter, and show filteredTasks. Each constituent that calls the hook gets its ain select state.
You’ll usage this hook successful the authorities and events workout later, truthful support the record moreover though the remainder of the task doesn’t import it.
You don’t request to create a civilization hook for each portion of logic, though. Keep elemental logic wrong the constituent erstwhile that makes the codification easier to follow.
How do React Router and API information move components into an app?
React Router and API information move your components into an app by connecting components to URLs and filling them pinch information from outer sources.
In the task tracker, React Router will adhd dashboard, task details, and astir views, while API information will supply tasks that aren’t hardcoded successful the project.
Add pages pinch React Router
To adhd pages pinch React Router, instal it first, past wrap App pinch BrowserRouter and representation URL paths to components.
Install the latest type of React Router:
npm instal react-routerImportant
Important! React Router v7 and later usage react-router arsenic the main package. Older tutorials usage react-router-dom, truthful import the routing APIs utilized successful this task from react-router.
Next, update src/main.jsx:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router'; import './index.css'; import App from './App.jsx'; createRoot(document.getElementById('root')).render( <StrictMode> <BrowserRouter> <App /> </BrowserRouter> </StrictMode>, );BrowserRouter lets React Router usage the browser URL to find which position to display.
Create src/pages/About.jsx:
function About() { return ( <main className="app"> <h2>About</h2> <p>A task locator built while learning React.</p> </main> ); } export default About;Then, create src/pages/TaskDetails.jsx:
import { useParams } from 'react-router'; function TaskDetails({ tasks }) { const { taskId } = useParams(); const task = tasks.find( (task) => task.id === Number(taskId) ); if (!task) { return <p>Task not found.</p>; } return ( <main className="app"> <h2>{task.title}</h2> <p>Status: {task.done ? 'Done' : 'Open'}</p> </main> ); } export default TaskDetails;The :taskId portion of the URL identifies which task to display.
In src/App.jsx, support your existing authorities and task functions. Import Routes, Route, and the caller page components:
import { Route, Routes } from 'react-router'; import About from './pages/About.jsx'; import TaskDetails from './pages/TaskDetails.jsx';Then, switch the existent return connection successful App with:
return ( <> <Header /> <Routes> <Route path="/" element={ <main className="app"> <TaskForm onAdd={addTask} /> <TaskList tasks={tasks} onToggle={toggleTask} onDelete={deleteTask} /> </main> } /> <Route path="/tasks/:taskId" element={<TaskDetails tasks={tasks} />} /> <Route path="/about" element={<About />} /> </Routes> </> );The / way displays your dashboard, /tasks/:taskId displays an individual task, and /about displays the astir page.
To navigate betwixt the main views, import Link into Header.jsx:
import { Link } from 'react-router';Then, adhd these links wrong the <header> element:
<nav> <Link to="/">Dashboard</Link> <Link to="/about">About</Link> </nav>
To unfastened the task specifications page, import Link into TaskItem.jsx and adhd this nexus wrong the task item:
<Link to={`/tasks/${id}`}> View details </Link>
You tin now move betwixt views without reloading the full page.
Fetch and show API data
You tin fetch and show API information successful the task locator by converting the consequence to the aforesaid information building your existing task components use.
JSONPlaceholder stores a task’s completion position successful completed, while your task locator uses done. In src/components/ApiTasks.jsx, replace:
setTasks(data);with:
const apiTasks = data.map((task) => ({ id: task.id, title: task.title, done: task.completed, })); setTasks(apiTasks);Then, update the task position successful the returned JSX:
{task.done ? '✓ ' : '○ '} {task.title}Each API task now has the aforesaid id, title, and done properties arsenic the task objects utilized elsewhere successful the project. Keeping 1 accordant building intends your components don’t request abstracted logic for section and API data.
Show loading and correction states
To show loading and correction states, way the petition position successful ApiTasks.jsx and show feedback earlier the task list.
Add 2 authorities values beneath the existing tasks state:
const [loading, setLoading] = useState(true); const [error, setError] = useState('');In loadTasks, switch the existent catch artifact with:
} drawback { if (!ignore) { setError('Could not load tasks.'); } }Then, adhd a finally artifact aft it:
finally { if (!ignore) { setLoading(false); } }Before the constituent returns the task list, add:
if (loading) { return <p>Loading tasks...</p>; } if (error) { return <p>{error}</p>; }Now Loading tasks… appears while the petition is running, Could not load tasks. appears erstwhile it fails, and the task database appears aft a successful request.
For practice, temporarily switch the API endpoint pinch https://jsonplaceholder.typicode.com/not-a-real-endpoint and corroborate that the correction connection appears.
Restore the original endpoint aft testing it. Then, region <ApiTasks /> and its import from App.jsx earlier continuing.
How to build a mini React task from commencement to finish
To build a mini React task from commencement to finish, harvester the components, state, forms, hooks, routing, and API techniques into 1 app.
You’ll proceed pinch the task locator task you built earlier, truthful you don’t request to create different one.
Complete each measurement and cheque the consequence earlier continuing. This makes it easier to drawback problems earlier you adhd different feature.
1. Create the task structure
Create the task building by separating reusable components and page-level views wrong src. The last task locator only needs a fewer files:
react-task-tracker/ ├── index.html ├── package.json ├── vite.config.js └── src/ ├── components/ │ ├── Header.jsx │ ├── TaskForm.jsx │ ├── TaskItem.jsx │ └── TaskList.jsx ├── pages/ │ ├── About.jsx │ ├── Dashboard.jsx │ └── TaskDetails.jsx ├── App.css ├── App.jsx ├── index.css └── main.jsxThis building covers the halfway task tracker. The exercises later adhd optional files specified arsenic EmptyState.jsx, TaskStats.jsx, useTaskFilter.js, and ApiTaskDetails.jsx.
Use components for reusable interface elements specified arsenic the header, form, and task items. Use pages for complete views that React Router connects to URLs.
Create immoderate missing folders successful your editor. On macOS aliases Linux, you tin besides run:
mkdir -p src/components src/pagesCheckpoint: Confirm that components and pages look wrong src and that the files are organized arsenic shown above.
2. Build the layout components
You tin build the task locator layout by adding a shared header and a centered contented area for the app’s main features.
Create src/components/Header.jsx:
function Header() { return ( <header className="header"> <h1>Task tracker</h1> </header> ); } export default Header;Then, switch src/App.jsx with:
import Header from './components/Header.jsx'; import './App.css'; function App() { return ( <> <Header /> <main className="container"> <p>Your task locator is fresh for tasks.</p> </main> </> ); } export default App;Next, switch the starter styles successful src/index.css pinch the world styles:
:root { font-family: Arial, sans-serif; color: #1f2937; background: #f3f4f6; } * { box-sizing: border-box; } body { margin: 0; } button, input { font: inherit; } button { cursor: pointer; }Then, switch src/App.css pinch the layout styles:
.header { padding: 1rem 1.5rem; background: #ffffff; border-bottom: 1px coagulated #d1d5db; } .header h1 { margin: 0; } .container { width: min(720px, calc(100% - 2rem)); margin: 2rem auto; }Keeping the world rules successful index.css prevents Vite’s starter styles from affecting the page layout. App.css tin past incorporate styles circumstantial to the task locator interface.
Checkpoint: You should spot the Task tracker heading supra the placeholder text, pinch the contented centered connected a ray grey background.
3. Build the task list
To build the task list, usage TaskItem to show each task and TaskList to render the afloat collection.
Create src/components/TaskItem.jsx:
function TaskItem({ id, title, done, onToggle, onDelete, }) { return ( <li className={`task-item ${done ? 'done' : ''}`}> <span className="task-title"> {done ? '✓ ' : '○ '} {title} </span> <div className="task-actions"> <button type="button" onClick={() => onToggle(id)} > {done ? 'Mark open' : 'Mark done'} </button> <button type="button" onClick={() => onDelete(id)} > Delete </button> </div> </li> ); } export default TaskItem;Then, create src/components/TaskList.jsx:
import TaskItem from './TaskItem.jsx'; function TaskList({ tasks, onToggle, onDelete, }) { if (tasks.length === 0) { return <p>No tasks yet.</p>; } return ( <ul className="task-list"> {tasks.map((task) => ( <TaskItem key={task.id} id={task.id} title={task.title} done={task.done} onToggle={onToggle} onDelete={onDelete} /> ))} </ul> ); } export default TaskList;Add these styles to src/App.css:
.task-list { display: grid; gap: 0.75rem; padding: 0; margin: 1rem 0 0; list-style: none; } .task-item { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem; background: #ffffff; border: 1px coagulated #d1d5db; border-radius: 0.5rem; } .task-item.done .task-title { color: #6b7280; text-decoration: line-through; } .task-actions { display: flex; gap: 0.5rem; }TaskList will look erstwhile App passes task information and action handlers to it.
Checkpoint: Save TaskItem.jsx and TaskList.jsx, past cheque that the task still runs without errors successful the browser aliases developer console.
4. Add task state
Add the shared task authorities and action functions successful App.jsx truthful TaskList tin display, complete, reopen, and delete tasks. Start pinch 2 section tasks truthful you tin verify these actions earlier connecting the app to API data.
Replace src/App.jsx with:
import { useState } from 'react'; import Header from './components/Header.jsx'; import TaskList from './components/TaskList.jsx'; import './App.css'; const initialTasks = [ { id: 1, title: 'Build the task list', done: true, }, { id: 2, title: 'Add React state', done: false, }, ]; function App() { const [tasks, setTasks] = useState(initialTasks); usability toggleTask(id) { setTasks((currentTasks) => currentTasks.map((task) => task.id === id ? { ...task, done: !task.done } : task ) ); } usability deleteTask(id) { setTasks((currentTasks) => currentTasks.filter((task) => task.id !== id) ); } return ( <> <Header /> <main className="container"> <TaskList tasks={tasks} onToggle={toggleTask} onDelete={deleteTask} /> </main> </> ); } export default App;Keep tasks successful App.jsx truthful the dashboard and task-details page tin usage the aforesaid task information erstwhile you adhd routes later.
Checkpoint: Select Mark done aliases Mark open and corroborate that the task position changes immediately. Delete a task and corroborate that it disappears from the list. Delete some tasks to corroborate that No tasks yet. appears.
5. Add the task form
Add the task shape by connecting TaskForm to App truthful you tin create validated tasks and adhd them to the shared task list.
Create src/components/TaskForm.jsx:
import { useState } from 'react'; function TaskForm({ onAdd }) { const [title, setTitle] = useState(''); usability handleSubmit(event) { event.preventDefault(); const trimmedTitle = title.trim(); if (trimmedTitle === '') { return; } onAdd(trimmedTitle); setTitle(''); } return ( <form className="task-form" onSubmit={handleSubmit} > <label htmlFor="task-title"> Task name </label> <div className="task-form-row"> <input id="task-title" name="task-title" type="text" placeholder="Add a caller task..." value={title} onChange={(event) => setTitle(event.target.value) } /> <button type="submit"> Add task </button> </div> </form> ); } export default TaskForm;Next, import TaskForm into src/App.jsx:
import TaskForm from './components/TaskForm.jsx';Add addTask wrong App:
function addTask(title) { const newTask = { id: Date.now(), title, done: false, }; setTasks((currentTasks) => [ ...currentTasks, newTask, ]); }Then, render TaskForm supra TaskList:
<TaskForm onAdd={addTask} /> <TaskList tasks={tasks} onToggle={toggleTask} onDelete={deleteTask} />Add the shape styles to src/App.css:
.task-form { display: grid; gap: 0.5rem; margin-bottom: 1.5rem; } .task-form-row { display: flex; gap: 0.5rem; } .task-form input { flex: 1; min-width: 0; padding: 0.75rem; }addTask creates each caller task successful the aforesaid id, title, and done format utilized by the remainder of the app, truthful recently added tasks activity pinch the existing toggle and delete actions.
Checkpoint: Add a valid task and corroborate that it appears successful the list. Mark it done, reopen it, and delete it to corroborate that caller tasks activity pinch the existing actions. Then, taxable a title containing only spaces and corroborate that nary task is added.
6. Add routes
To adhd routes, create dashboard, task-details, and astir pages, past link them to URLs pinch React Router.
First, update src/components/Header.jsx truthful users tin navigate betwixt the main pages:
import { Link } from 'react-router'; function Header() { return ( <header className="header"> <h1>Task tracker</h1> <nav> <Link to="/">Dashboard</Link> <Link to="/about">About</Link> </nav> </header> ); } export default Header;Next, create src/pages/Dashboard.jsx to group the task form, task list, and completion count connected the main page:
import TaskForm from '../components/TaskForm.jsx'; import TaskList from '../components/TaskList.jsx'; function Dashboard({ tasks, onAdd, onToggle, onDelete, }) { const full = tasks.length; const completed = tasks.filter( (task) => task.done ).length; return ( <section> <p className="stats"> {completed} of {total} tasks completed </p> <TaskForm onAdd={onAdd} /> <TaskList tasks={tasks} onToggle={onToggle} onDelete={onDelete} /> </section> ); } export default Dashboard;Create src/pages/About.jsx for the 2nd main view:
function About() { return ( <section> <h2>About this app</h2> <p> This task locator is simply a beginner React project for practicing components, state, forms, hooks, routing, and API data. </p> </section> ); } export default About;Then, create src/pages/TaskDetails.jsx truthful each task tin person its ain URL:
import { useParams } from 'react-router'; function TaskDetails({ tasks }) { const { taskId } = useParams(); const task = tasks.find( (task) => task.id === Number(taskId) ); if (!task) { return <p>Task not found.</p>; } return ( <section> <h2>{task.title}</h2> <p>Status: {task.done ? 'Done' : 'Open'}</p> </section> ); } export default TaskDetails;The :taskId portion of /tasks/:taskId is simply a move URL segment. For example, opening /tasks/2 gives useParams() a taskId worth of “2”. Number(taskId) converts that drawstring to a number truthful it tin lucifer the numeric task IDs.
Next, adhd a nexus from each task to its specifications page. Import Link astatine the apical of src/components/TaskItem.jsx:
import { Link } from 'react-router';Then, adhd the View details nexus wrong <div className=”task-actions”>, supra the first button:
<div className="task-actions"> <Link to={`/tasks/${id}`}> View details </Link> <button type="button" onClick={() => onToggle(id)} > {done ? 'Mark open' : 'Mark done'} </button> <button type="button" onClick={() => onDelete(id)} > Delete </button> </div>Enable browser routing successful src/main.jsx:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router'; import './index.css'; import App from './App.jsx'; createRoot(document.getElementById('root')).render( <StrictMode> <BrowserRouter> <App /> </BrowserRouter> </StrictMode>, );Next, import the routing components and page components into src/App.jsx:
import { Route, Routes } from 'react-router'; import Dashboard from './pages/Dashboard.jsx'; import About from './pages/About.jsx'; import TaskDetails from './pages/TaskDetails.jsx';Replace the existent return connection successful App with:
return ( <> <Header /> <main className="container"> <Routes> <Route path="/" element={ <Dashboard tasks={tasks} onAdd={addTask} onToggle={toggleTask} onDelete={deleteTask} /> } /> <Route path="/tasks/:taskId" element={ <TaskDetails tasks={tasks} /> } /> <Route path="/about" element={<About />} /> </Routes> </main> </> );The / way shows the dashboard, /tasks/:taskId shows the selected task, and /about shows accusation astir the project.
Finally, update the header styles successful src/App.css and adhd styling for its navigation:
.header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 1.5rem; background: #ffffff; border-bottom: 1px coagulated #d1d5db; } .header nav { display: flex; gap: 1rem; }Checkpoint: Open Dashboard and About, past prime View details connected a task. Each action should update the URL and show the corresponding page without a afloat page reload.
7. Fetch starter data
Fetch the starter tasks into App.jsx truthful the dashboard and task-details page tin usage the aforesaid API-loaded task data.
Remove the initialTasks array, past update the React import astatine the apical of src/App.jsx:
import { useEffect, useState } from 'react';Replace useState(initialTasks) pinch authorities for the tasks and petition status:
const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState('');Then, adhd the API petition wrong App:
useEffect(() => { fto disregard = false; async usability loadTasks() { effort { const consequence = await fetch( 'https://jsonplaceholder.typicode.com/todos' ); if (!response.ok) { propulsion caller Error( `Request grounded pinch position ${response.status}` ); } const information = await response.json(); const apiTasks = data .slice(0, 4) .map((task) => ({ id: task.id, title: task.title, done: task.completed, })); if (!ignore) { setTasks(apiTasks); } } drawback { if (!ignore) { setError('Could not load tasks.'); } } yet { if (!ignore) { setLoading(false); } } } loadTasks(); return () => { disregard = true; }; }, []);JSONPlaceholder uses completed for each task’s status, while the task locator uses done. The map() telephone converts the API consequence to the aforesaid id, title, and done building utilized passim the app.
Next, walk loading and error to Dashboard successful the / route:
<Route path="/" element={ <Dashboard tasks={tasks} loading={loading} error={error} onAdd={addTask} onToggle={toggleTask} onDelete={deleteTask} /> } />Update the Dashboard parameters:
function Dashboard({ tasks, loading, error, onAdd, onToggle, onDelete, }) {Then, adhd these checks earlier calculating total and completed:
if (loading) { return <p>Loading tasks...</p>; } if (error) { return <p>{error}</p>; }The dashboard now shows Loading tasks… while the petition runs and Could not load tasks. if the petition fails.
Pass the aforesaid petition authorities to TaskDetails truthful a nonstop sojourn to a task URL doesn’t show Task not found. earlier the tasks decorativeness loading:
<Route path="/tasks/:taskId" element={ <TaskDetails tasks={tasks} loading={loading} error={error} /> } />Then, update src/pages/TaskDetails.jsx:
import { useParams } from 'react-router'; function TaskDetails({ tasks, loading, error, }) { const { taskId } = useParams(); if (loading) { return <p>Loading task...</p>; } if (error) { return <p>{error}</p>; } const task = tasks.find( (task) => task.id === Number(taskId) ); if (!task) { return <p>Task not found.</p>; } return ( <section> <h2>{task.title}</h2> <p>Status: {task.done ? 'Done' : 'Open'}</p> </section> ); } export default TaskDetails;Checking loading earlier looking for the task prevents the specifications page from treating an quiet task array arsenic a missing task while the API petition is still running.
Tasks you add, complete, reopen, aliases delete aft loading stay successful React authorities for the existent session. Refreshing the page shows the 4 starter tasks again because the app doesn’t prevention those changes to imperishable storage.
Checkpoint: Refresh the dashboard and corroborate that Loading tasks… appears earlier 4 starter tasks load. Then, unfastened a task specifications page and refresh it directly. You should spot Loading task… earlier the selected task appears alternatively of concisely seeing Task not found.

8. Test and polish the app
Test and polish the app by adding responsive styles, checking its main features and routes, and creating a accumulation build.
First, adhd this responsive styling to src/App.css:
@media (max-width: 600px) { .header { align-items: flex-start; flex-direction: column; } .task-form-row { flex-direction: column; } .task-item { align-items: stretch; flex-direction: column; } .task-actions { flex-wrap: wrap; } }At widths of 600px aliases less, the navigation, form, and task controls now person much room by stacking aliases wrapping alternatively of staying successful a azygous row.

Next, trial the complete app:
- Refresh the dashboard and corroborate that the loading connection is followed by 4 starter tasks.
- Add a valid task and corroborate that it appears once.
- Submit an quiet aliases whitespace-only title and corroborate that nary task is added.
- Mark an unfastened task arsenic done and corroborate that its position and completed count update.
- Reopen a completed task and corroborate that the count updates again.
- Delete a task and corroborate that it disappears and the full count changes.
- Select View details and corroborate that the correct task title and position appear.
- Refresh a task-details page straight and corroborate that Loading task… appears earlier the task loads.
- Navigate betwixt Dashboard and About, past trial the browser’s backmost and guardant buttons.
- Temporarily usage an invalid API endpoint and corroborate that Could not load tasks. appears. Restore the moving endpoint afterward.

- Resize the browser to a phone-width surface and corroborate that the header, form, task items, and action buttons stay usable.
- Check the developer console for React warnings aliases errors.
After the app passes these checks, create the accumulation build:
npm tally buildA successful build confirms that Vite tin compile the app for production.

Task changes still reset aft a refresh because the app stores them only successful React authorities alternatively than imperishable storage.
Checkpoint: Confirm that the app passes the checklist without React warnings aliases errors and that npm tally build completes successfully.
What React exercises should beginners complete?
Beginners should complete React exercises connected JSX and components, props, authorities and events, forms, routing, and API data.
The exercises beneath widen your vanished task locator pinch optional features that thief you believe each conception 1 astatine a time.
JSX and components exercise
For the JSX and components exercise, create a reusable EmptyState.jsx constituent that appears erstwhile the task database is empty.
Your constituent should:
- Return valid JSX pinch 1 genitor element.
- Include the heading No tasks yet.
- Include a short connection that tells you to adhd your first task.
- Replace the existing No tasks yet. paragraph successful TaskList.jsx.
Expected output: Delete each tasks, and the caller empty-state connection should look alternatively of the task list.
Props exercise
Practice props by replacing the existing dashboard stats pinch a reusable TaskStats.jsx constituent that receives the total, completed, and remaining task counts from Dashboard.jsx.
Create src/components/TaskStats.jsx and adhd props for total, completed, and remaining.
In Dashboard.jsx, cipher the remaining tasks:
const remaining = full - completed;Then, import TaskStats:
import TaskStats from '../components/TaskStats.jsx';Replace the existing stats paragraph:
<p className="stats"> {completed} of {total} tasks completed </p>with:
<TaskStats total={total} completed={completed} remaining={remaining} />Inside TaskStats.jsx, show each 3 values pinch JSX.
Expected output: The dashboard shows 1 summary, specified arsenic 4 total, 1 done, 3 remaining. Adding, completing, reopening, aliases deleting a task should update the values automatically.
State and events exercise
In the authorities and events exercise, usage the useTaskFilter hook to adhd All, Active, and Done select buttons to the dashboard.
In Dashboard.jsx, import the hook:
import useTaskFilter from '../hooks/useTaskFilter.js';Then, telephone it wrong Dashboard:
const { filter, setFilter, filteredTasks, } = useTaskFilter(tasks);Add the select buttons supra TaskList:
<div className="task-filters"> <button type="button" onClick={() => setFilter('all')} > All </button> <button type="button" onClick={() => setFilter('active')} > Active </button> <button type="button" onClick={() => setFilter('done')} > Done </button> </div>Finally, walk filteredTasks to TaskList alternatively of tasks:
<TaskList tasks={filteredTasks} onToggle={onToggle} onDelete={onDelete} />
Expected output: All shows each task, Active shows tasks that aren’t complete, and Done shows completed tasks. Adding, completing, reopening, aliases deleting a task should update the filtered database automatically.
Forms exercise
For the forms exercise, adhd a due-date section to TaskForm, prevention the selected day pinch each caller task, and show it successful the task list.
Your changes should:
- Store the owed day pinch different useState telephone successful TaskForm.jsx.
- Add an input pinch type=”date” to the form.
- Require some the task title and owed day earlier calling onAdd.
- Pass the owed day to onAdd pinch the title.
- Update addTask truthful each caller task stores a dueDate property.
- Pass dueDate={task.dueDate} from TaskList.jsx to TaskItem.
- Add dueDate to the TaskItem usability parameters and show it erstwhile the task has a owed date.
- Clear some shape fields aft a valid submission.
For measurement 6, update the TaskItem telephone successful TaskList.jsx:
<TaskItem key={task.id} id={task.id} title={task.title} done={task.done} dueDate={task.dueDate} onToggle={onToggle} onDelete={onDelete} />Then, update the TaskItem parameters:
function TaskItem({ id, title, done, dueDate, onToggle, onDelete, }) {Display the day wherever it fits people successful the task markup, for example, beneath the title.

Expected output: A recently added task shows its selected owed date. The shape shouldn’t adhd a task erstwhile the title aliases owed day is missing.
Routing and API exercise
For the routing and API exercise, create a abstracted ApiTaskDetails.jsx page that loads 1 task from JSONPlaceholder utilizing the taskId way parameter.
Create src/pages/ApiTaskDetails.jsx:
import { Link, useParams } from 'react-router'; import { useEffect, useState } from 'react'; function ApiTaskDetails() { const { taskId } = useParams(); const [task, setTask] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); useEffect(() => { fto disregard = false; async usability loadTask() { setLoading(true); setError(''); effort { const consequence = await fetch( `https://jsonplaceholder.typicode.com/todos/${taskId}` ); if (!response.ok) { propulsion caller Error( `Request grounded pinch position ${response.status}` ); } const information = await response.json(); if (!ignore) { setTask(data); } } drawback { if (!ignore) { setError('Could not load task.'); } } yet { if (!ignore) { setLoading(false); } } } loadTask(); return () => { disregard = true; }; }, [taskId]); if (loading) { return <p>Loading task...</p>; } if (error) { return <p>{error}</p>; } return ( <section> <h2>{task.title}</h2> <p> Status: {task.completed ? 'Done' : 'Open'} </p> <Link to="/">Back to dashboard</Link> </section> ); } export default ApiTaskDetails;Next, import ApiTaskDetails into src/App.jsx:
import ApiTaskDetails from './pages/ApiTaskDetails.jsx';Then, adhd a abstracted way for the workout wrong Routes:
<Route path="/api-tasks/:taskId" element={<ApiTaskDetails />} />The taskId worth successful the URL determines which JSONPlaceholder task the page requests. For example, /api-tasks/1 requests task 1, while /api-tasks/2 requests task 2.
Expected output: Opening /api-tasks/1 shows Loading task… earlier displaying task 1 and its status. Changing the URL to different valid task ID loads that task, while an unsuccessful petition shows Could not load task. The Back to dashboard nexus returns you to the main task list.
What communal React mistakes should beginners avoid?
Common React mistakes beginners should debar see changing authorities directly, utilizing unstable database keys, misusing useEffect, and overcomplicating components aliases information flow.
| Mistake | Why it causes problems | Better approach |
| Changing authorities directly | React whitethorn not re-render erstwhile you alteration an existing array aliases entity and reuse the aforesaid reference. You tin besides accidentally alteration information that different codification still relies on | Create a caller array aliases entity pinch methods specified arsenic map(), filter(), aliases dispersed syntax, past walk it to the authorities setter |
| Using missing aliases unstable key values | React tin subordinate a rendered point pinch the incorrect information erstwhile you add, delete, aliases reorder database items. For example, an input worth aliases constituent authorities tin look connected the incorrect task | Use a unchangeable ID from the point data, specified arsenic task.id |
| Overusing useEffect | Using an effect to cipher values from existing authorities tin trigger an other render. An effect that updates 1 of its ain limitations tin besides tally many times and create an update loop | Calculate values during rendering and grip personification actions successful arena handlers. Use useEffect erstwhile you request to synchronize pinch thing extracurricular React |
| Building oversized components | A alteration to 1 characteristic tin require editing a record that besides contains unrelated form, list, routing, aliases data-loading logic. This makes it harder to find wherever a problem starts and alteration 1 characteristic without affecting another | Split the constituent erstwhile a portion of the interface has its ain clear responsibility, specified arsenic a form, task list, aliases navigation |
| Passing props done galore unused components | Every constituent betwixt the information root and its destination must judge and guardant the prop, moreover erstwhile it doesn’t usage the value. Renaming aliases changing that prop tin require edits crossed respective files | Keep authorities adjacent to the components that usage it. Move shared authorities to their closest communal parent, and see discourse erstwhile profoundly nested components request the aforesaid data |
| Adding precocious libraries excessively early | You person much APIs, configuration, and data-flow patterns to study astatine the aforesaid time. This tin make it unclear whether a worth aliases behaviour comes from React aliases the added library | Learn components, props, state, events, forms, and hooks first. Add a room erstwhile your task has a circumstantial problem it tin solve |
What should you do aft building your React app?
After building your task locally, deploy your React app truthful different group tin entree it online. Once it’s live, support improving the task arsenic you study caller React skills.
When deploying your app, take a reliable hosting supplier specified arsenic Hostinger. The React hosting plans see a free domain for 1 twelvemonth connected yearly plans.
They besides see free managed SSL certificates that stay progressive arsenic agelong arsenic your app is hosted pinch Hostinger, truthful you tin service it securely complete HTTPS.
After deployment, trial the unrecorded app to make judge it useful arsenic it did connected your section computer. Check the navigation, forms, task actions, API requests, and loading and correction states.
Because React Router handles routes successful the browser, immoderate hosts return a 404 correction erstwhile you refresh a URL specified arsenic /about. Set your big to service index.html for each routes to hole this.
Publishing your app isn’t the extremity of the project. You tin adhd persistent task retention truthful changes past a refresh aliases improve React performance to velocity up your app.
Focus connected 1 useful betterment astatine a clip truthful you tin understand and trial each alteration earlier adding another.

All of the tutorial contented connected this website is taxable to Hostinger's rigorous editorial standards and values.
English (US) ·
Indonesian (ID) ·