-
Notifications
You must be signed in to change notification settings - Fork 0
Project 6 Routing
จริงๆ แล้ว React เป็นแบบ Single Page App คือทั้งแอพรันบนหน้าเดียว แต่เราก็ยังสามารถประยุกต์ใช้ React กับ Library ต่างๆ เพื่อให้มันสามารถที่จะทำ Virtual Link ภายในได้ โดยในที่นี้เราจะใช้ Library ของ React-Router
- ติดตั้ง React Router
npm install --save react-router react-router-dom- Import Component ของ React Router ไปที่ App.js โดยตัวสำคัญๆ จะมี BrowserRouter, Routes และ Route โดยเป็นลักษระของการเป็น context เป็นชั้นๆ ไป
import { Routes, Route } from "react-router";
import { BrowserRouter } from "react-router-dom";
function App(){
...
return (
return (
<div>
...
<BrowserRouter basename='/'>
<Routes>
<Route path='/' element={<div>home</div>} />
<Route path='/hi' element={<div>hi</div>} />
</Routes>
</BrowserRouter>
....
</div>
)
}ลองดูผลการรัน ในหน้าแรกจะเห็นว่ามีคำว่า home ขึ้นมา ขณะที่เมื่อเราเปลี่ยนข้างบน Address bar ใส่ /hi เข้าไป มันจะเป็นคำว่า hi

- สร้างโฟลเดอร์ views อยู่ใน frontend/src ทำหน้าที่เก็บ Logic ในหน้าต่างๆ เราจะสร้าง 3 หน้าใหญ่ๆ ก่อนคือ รายการพนักงาน เพิ่มพนักงาน และ รายละเอียดพนักงาน โดยตอนนี้เรามีรายการพนักงานกับเพิ่มพนักงานแล้ว แต่ยังอยู่ในหน้าเดียวกัน ส่วนรายละเอียดพนักงานไว้ทำทีหลัง เราจะแยกออกมันเป็นหลายๆ หน้า
- ในโฟลเดอร์ views สร้างไฟล์
UserList.jsขึ้นมา (ชื่อไฟล์ตั้งเป็น Parcel Case) แล้วย้าย Logic จาก App.js ในส่วนของการแสดงตารางไปที่ UserList.js ตัวอย่างเช่น
import React, { useState, useEffect } from "react";
import {
Button,
Card,
CardContent,
Input,
LinearProgress,
Table,
} from "@mui/joy";
import axios from "axios";
import _ from "lodash";
function CreateUser() {
const [searchTerm, setSearchTerm] = useState("");
const [users, setUsers] = useState([]);
const [isReady, setIsReady] = useState(false);
const getAllUser = () => {
setIsReady(false);
axios
.get(`${process.env.REACT_APP_API_URL}/user`)
.then((res) => {
setUsers(res?.data?.rows);
setIsReady(true);
console.log("User ", res?.data?.rows);
})
.catch((error) => {
console.error("Error", error?.message);
});
};
useEffect(() => {
getAllUser();
return () => {};
}, []);
const handleDeleteUser = (userId) => {
axios
.delete(`${process.env.REACT_APP_API_URL}/user/${userId}`)
.then((res) => {
getAllUser();
})
.catch((error) => {
alert(error?.message);
console.error("Error", error?.message);
});
};
if (!isReady) {
return (
<div>
<LinearProgress />
</div>
);
}
return (
<div>
<div className='min-h-screen'>
<div className='flex justify-center flex-wrap'>
<div className='lg:w-3/4'>
<Card>
<CardContent>
<div>Search Box</div>
<Input
placeholder='Input Some Search Word'
onChange={(e) => setSearchTerm(e.target.value)}
/>
<div>
You Search <span className='text-blue-500'>{searchTerm}</span>
</div>
</CardContent>
</Card>
<div>
<h3 className='font-bold'>User List</h3>
<Table>
<thead>
<tr>
<th>ลำดับที่</th>
<th>ชื่อ</th>
<th>แผนก</th>
<th>ดำเนินการ</th>
</tr>
</thead>
{_.map(users, (eachUser, index) => (
<tr>
<td>{index + 1}</td>
<td>{eachUser?.name}</td>
<td>{eachUser?.department}</td>
<td>
<Button
color='danger'
onClick={() => handleDeleteUser(eachUser?._id)}
>
ลบ
</Button>
</td>
</tr>
))}
</Table>
</div>
</div>
</div>
</div>
</div>
);
}
export default CreateUser;และสร้างไฟล์ CreateUser.js
import React, { useState } from "react";
import { Button, Card, CardContent, Input, LinearProgress } from "@mui/joy";
import axios from "axios";
import { useForm, Controller } from "react-hook-form";
function CreateUser() {
const [searchTerm, setSearchTerm] = useState("");
const [isReady, setIsReady] = useState(true);
const { control, handleSubmit } = useForm();
const handleCreateUser = (data) => {
console.log("data", data);
setIsReady(false);
axios
.post(`${process.env.REACT_APP_API_URL}/user`, data)
.then((res) => {
axios.get(`${process.env.REACT_APP_API_URL}/user`).then((res) => {
setIsReady(true);
});
})
.catch((error) => {
console.error("Error", error?.message);
});
};
if (!isReady) {
return (
<div>
<LinearProgress />
</div>
);
}
return (
<div>
<div className='min-h-screen'>
<div className='flex justify-center flex-wrap'>
<div className='lg:w-3/4 '>
<div className='my-1 font-semibold text-lg'>เพิ่มพนักงานใหม่</div>
<Card>
<CardContent>
<form onSubmit={handleSubmit(handleCreateUser)}>
<div>ชื่อ</div>
<Controller
name='name'
control={control}
render={({ field }) => (
<Input {...field} placeholder='ชื่อพนักงาน' />
)}
/>
<div>แผนก</div>
<Controller
name='department'
control={control}
render={({ field }) => (
<Input {...field} placeholder='แผนก' />
)}
/>
<div>
<Button type='submit'>บันทึก</Button>
</div>
</form>
</CardContent>
</Card>
</div>
<div className='lg:w-3/4'>
<Card>
<CardContent>
<div>Search Box</div>
<Input
placeholder='Input Some Search Word'
onChange={(e) => setSearchTerm(e.target.value)}
/>
<div>
You Search <span className='text-blue-500'>{searchTerm}</span>
</div>
</CardContent>
</Card>
<div></div>
</div>
</div>
</div>
</div>
);
}
export default CreateUser;และเราจะมีไฟล์ที่มีโครงสร้างอย่างนี้

App.js ก็จะเหลือประมาณนี้
import React from "react";
import { Routes, Route } from "react-router";
import { BrowserRouter } from "react-router-dom";
import Footer from "./Components/Footer";
import Topbar from "./Components/Topbar";
function App() {
return (
<div>
<Topbar appTitle='IARC Devboard' />{" "}
<BrowserRouter basename='/'>
<Routes>
<Route path='/' element={<div>home</div>} />
<Route path='/hi' element={<div>hi</div>} />
</Routes>
</BrowserRouter>
<Footer />
</div>
);
}
export default App;- Import File ทั้ง 2 Files ใน View เข้ามาที่ App.js และมาเติมเต็ม Router ของเรา โดยเราเอา path='/' ชี้ไปที่รายการพนักงานทุกคน ส่วน '/create' ไปที่ CreateUser
import React from "react";
import { Routes, Route } from "react-router";
import { BrowserRouter } from "react-router-dom";
import Footer from "./Components/Footer";
import Topbar from "./Components/Topbar";
function App() {
return (
<div>
<BrowserRouter basename='/'>
<Topbar appTitle='IARC Devboard' />{" "}
<Routes>
<Route path='/create' element={<CreateOneUser />} />
<Route path='/' element={<UserList />} />
</Routes>
<Footer />
</BrowserRouter>
</div>
);
}
export default App;- ลองเปลี่ยนคำที่หลัง Address Bar ปรับปรุงแล้วดูผล
- เข้าไปใน Component ของ NavBar แล้วไปใส่ลิงค์ไปยังหน้าต่าง ๆ แล้วเปลี่ยน tag a href เป็น
import { Link } from "react-router-dom";
function TopBar(){
return <div>
<li>
<Link
to='/'
className='block py-2 pl-3 pr-4 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 md:dark:text-blue-500'
aria-current='page'
>
Home
</Link>
</li>
<li>
<Link
to='/create'
className='block py-2 pl-3 pr-4 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700'
>
Create User
</Link>
</li>
</div>
}- ลองบันทึก และลองคลิกเพื่อเปลี่ยนไปแต่ละหน้าดู
- สร้างหน้าสำหรับทำรายละเอียดพนักงาน โดยเราจะสร้างว่า DetailUser.js ใน views แล้ว import เข้าไปที่ App.js
import React from "react";
function DetailUser() {
return <div>DetailUser</div>;
}
export default DetailUser;สร้างเป็น Route ตัวหนึ่ง ซึ่งมี Path ที่มีลักษณะเป็น variable ด้วย โดยเมื่อเราเขียน : ไว้ด้านหน้าฟิลด์ไหน มันจะกลายเป็นตัวแปรทันที เช่น /:variableName จะเป็นตัวแปรชื่อ variableName โดยในที่นี้เราจะทำเป็นตัวแปรชื่อ id ใน Route ของ DetailUser โดยมี Path เป็น /detail/:id
<Route path='/detail/:id' element={<DetailUser />} />จากนั้นถ้าเรามาที่หน้า detail เฉยๆ มันจะไม่ได้มาที่ Route ของเรา
ขณะที่เมื่อเราใส่ ID เป็นอะไรสักอย่าง ก็จะออกมาที่หน้า Detail User

- ใส่ลิงค์ รายละเอียดไปที่ตารางของ User List และใส่ลิงค์ ที่เอามาจาก react-router-dom มาครอบ Button อีกที โดยในลิงค์เราส่ง ID ไปด้วย
import { Link } from "react-router-dom"; <Link to={`/detail/${eachUser?._id}`}>
<Button>รายละเอียด</Button>
</Link>
- คลิกปุ่มรายละเอียด เราจะมีหน้า Detail User ที่มี path parameter id ตามที่เราส่งมา
- ใน DetailUser ดึงพารามิเตอร์
useParamsออกมาจาก react-router หรือ react-router-dom ก็ได้ สร้างตัวแปร params จาก useParams() จากนั้นลอง console.log params ออกมา
import React from "react";
import { useParams } from "react-router";
function DetailUser() {
const params = useParams();
console.log("params", params);
return <div>DetailUser</div>;
}
export default DetailUser;จะเห็น parameter ต่างๆ ลิสต์ออกมา โดยของเรา เราจะมีตัวเดียว ก็คือ id ซึ่งจะเป็น id ตัวเดียวกันกับที่ปรากฏบน Address bar ด้านบน

- สร้าง useEffect ทำหน้าที่การไปหาข้อมูล User คนเดียวออกมา โดยใช้ findOne หรือส่ง GET พร้อมกับ id ไปยัง Backend
const params = useParams();
const [isReady, setIsReady] = useState(false);
const [data, setData] = useState({});
useEffect(() => {
axios
.get(`${process.env.REACT_APP_API_URL}/user/${params.id}`)
.then((res) => {
setData(res.data);
setIsReady(true);
});
return () => {};
}, [params]);
เราก็สามารถเอา data มาใช้แสดงข้อมูลต่าง ๆ ได้