2024. 3. 24. 16:27ㆍDaily Codig Reminder
라우팅
메뉴링크활성화피드백_NaviLink이용
import React from 'react';
import { NavLink } from 'react-router-dom';
import classes from './MainNavigation.module.css'
import { Link } from 'react-router-dom';
function MainNavigation(props) {
return (
<>
<NavLink
to="/"
className={({isActive}) => {
return isActive ? classes.menu : undefined;
}}>
Home
</NavLink><br/>
<NavLink
to="/"
className={({isActive}) => {
return isActive ? classes.a : undefined;
}}>
products
</NavLink><br/>
</>
);
}
export default MainNavigation;
css
a{
text-decoration: none;
color: blue;
}
.menu{
color: red;
text-decoration: underline;
}

프로그래밍이용한링크처리_useNavigate
import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
function Home(props) {
const naviagte = useNavigate();
const handleEvent = () => {
naviagte("/products");
};
return (
<div>
<h1>My Home Page</h1>
<p>
Go to <Link to="/products"> the list of products</Link>
</p>
<p>
<button onClick={handleEvent} >products 로 이동</button>
</p>
</div>
);
}
export default Home;

동적라우팅1_PathVariable방식_useParams
routing
경로지정시 / 로 시작하면 절대 경로이고 아니면 상대 경로이다.
<Link> 를 이용한 상대 경로 지정시 relative=“route|path” 속성값을 사용할 수 있다. 기본값은 route 이다.
{path: '/products/:productId', element: <ProductDetailPage />
<Link to=“..” relative=“ route”>back</Link> route로 지정하면 /products/2 가 하나의 route 경로이기 때문에
상위 경로로 가면 / 가 된다.
<Link to=“..” relative=“ path”>back</Link> path로 지정하면 /products/2 는 두개의 path 경로이기 때문에
상위 경로가 가면 /products 가 된다.
import React from 'react';
import {Link, useParams } from 'react-router-dom';
function ProductDetails(props) {
const params = useParams();
return (
<div>
<h1>Product Details!</h1>
<p>{params.productId}</p>
{/*relative='route' 하나의 경로 home 으로*/}
<Link to=".." relative='route'>
back1
</Link> <br/>
{/*relative='route' 두개의 경로 products 로*/}
<Link to=".." relative='path'>
back2
</Link> <br/>
{/*relative='' 안쓰면 home 으로(route방식)*/}
<Link to=".." >
back3
</Link> <br/>
</div>
);
}
export default ProductDetails;
import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
children : [
{path: "/" ,element: <Home/>},
{path: "/products", element: <Products/>},
{path: '/products/:productId', element: <ProductDetails/>} ///////추가
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
)
}
export default App;

동적라우팅2_QueryString방식_useSearchParams
import React from 'react';
const PRODUCTS = [
{id: "p1", title: "Product 1"},
{id: "p2", title: "Product 2"},
{id: "p3", title: "Product 3"},
]
function Products(props) {
return (
<div>
<h1>The Products Page(PathVariable 방식)</h1>
<ul>
{PRODUCTS.map(product => (
<li key={product.id}>
<a href={`/products/${product.id}`}>{product.title}</a>
</li>
))}
</ul>
<h1>The Products Page2(QueryString)</h1>
<ul>
{PRODUCTS.map(product => (
<li key={product.id}>
<a href={`/products2/?prod_id=${product.id}`}>{product.title}</a>
</li>
))}
</ul>
</div>
);
}
export default Products;
import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import ProductDetails2 from './pages/ProductDetails2';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
children : [
{path: "/" ,element: <Home/>},
{path: "/products", element: <Products/>},
{path: '/products/:productId', element: <ProductDetails/>}, ///////추가
{path: '/products2', element: <ProductDetails2/>},
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
)
}
export default App;
import React from 'react';
import {Link, useSearchParams } from 'react-router-dom';
function ProductDetails2(props) {
const [searchParams] = useSearchParams();
const prod_id = searchParams.get("prod_id");
return (
<div>
<h1>Product Details2!</h1>
<p>{prod_id}</p>
{/*relative='route' 하나의 경로 home 으로*/}
<Link to=".." relative='route'>
back1
</Link> <br/>
{/*relative='route' 두개의 경로 products 로*/}
<Link to=".." relative='path'>
back2
</Link> <br/>
{/*relative='' 안쓰면 home 으로(route방식)*/}
<Link to=".." >
back3
</Link> <br/>
</div>
);
}
export default ProductDetails2;

Routing09_loader
loader함수1기본
import React from 'react';
import { NavLink } from 'react-router-dom';
import classes from './MainNavigation.module.css'
import { Link } from 'react-router-dom';
function MainNavigation(props) {
return (
<>
<NavLink
to="/"
className={({isActive}) => {
return isActive ? classes.menu : undefined;
}}>
Home
</NavLink><br/>
<NavLink
to="/products"
className={({isActive}) => {
return isActive ? classes.a : undefined;
}}>
products
</NavLink><br/>
<NavLink
to="/users"
className={({isActive}) => {
return isActive ? classes.menu : undefined;
}}>
Users
</NavLink><br/>
</>
);
}
export default MainNavigation;
import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import ProductDetails2 from './pages/ProductDetails2';
import UsersPage from './pages/User';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
children : [
{path: "/" ,element: <Home/>},
{path: "/products", element: <Products/>},
{path: "/users", element: <UsersPage/>,
loader: async function () {
console.log("loader>>>>>");
const response = await fetch ("https://reqres.in/api/users?page=2");
const resData = await response.json();
return resData.data;
}
}, ////////////////추가
{path: '/products/:productId', element: <ProductDetails/>}, ///////추가
{path: '/products2', element: <ProductDetails2/>},
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
)
}
export default App;
import React from 'react';
import UserList from '../components/UserList';
import { useLoaderData } from 'react-router-dom';
function UsersPage(props) {
const events = useLoaderData(); //App.js 의 데이터를 로드
return (
<div>
<h1>The Users Page</h1>
<UserList events={events}/>
</div>
);
}
export default UsersPage;
import React from 'react';
function UserList({ events }) {
if (!events || !events.length) {
return <div>No users available.</div>;
}
return (
<div>
<table border="1">
<thead>
<tr>
<th>아이디</th>
<th>이름</th>
<th>사진</th>
</tr>
</thead>
<tbody>
{events.map((user, idx) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default UserList;

axios 버전
loader: async function () {
console.log("loader>>>>");
let resData;
await axios.get("https://reqres.in/api/users?page=2",{
}).then(
function(res){
console.log("axios내부",res)
resData = res.data.data;
}).catch(
(error) => {
throw new Error ("목록 로딩 시 에러 발생")
}
)
return resData;
UsersList에서직접loader데이터사용
import React from 'react';
import { useLoaderData } from 'react-router-dom';
function UserList() {
const events = useLoaderData();
if (!events || !events.length) {
return <div>No users available.</div>;
}
return (
<div>
<table border="1">
<thead>
<tr>
<th>아이디</th>
<th>이름</th>
<th>사진</th>
</tr>
</thead>
<tbody>
{events.map((user, idx) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default UserList;
import React from 'react';
import UserList from '../components/UserList';
import { useLoaderData } from 'react-router-dom';
function UsersPage(props) {
const events = useLoaderData(); //App.js 의 데이터를 로드
return (
<div>
<h1>The Users Page</h1>
<UserList />
</div>
);
}
export default UsersPage;

UsersList에서직접loader데이터사용2_id이용
import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import ProductDetails2 from './pages/ProductDetails2';
import UsersPage from './pages/User';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import axios from 'axios';
import { useFetcher } from 'react-router-dom';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
////////////////////////////////////////
id:"root",/////////////////////////
loader: async function () {
console.log("loader root >>>>>");
const response =await fetch("https://reqres.in/api/users?page=1");
const resData = await response.json();
return resData.data;
},
children: [
{ path: "/", element: <Home/> },
{ path: "/products", element: <Products/> },
{
path: "/users/",
element: <UsersPage/>,
loader: async function () {
console.log("loader>>>>>");
try {
const response = await axios.get("https://reqres.in/api/users?page=2");
return response.data.data;
} catch (error) {
console.error("Error loading users:", error);
return [];
}
}
}, ////////////////추가
{ path: '/products/:productId', element: <ProductDetails/> }, ///////추가
{ path: '/products2', element: <ProductDetails2/> },
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
);
}
export default App;
import React from 'react';
import { useLoaderData, useRouteLoaderData } from 'react-router-dom';
function UserList() {
const events = useRouteLoaderData("root");
if (!events || !events.length) {
return <div>No users available.</div>;
}
return (
<div>
<table border="1">
<thead>
<tr>
<th>아이디</th>
<th>이름</th>
<th>사진</th>
</tr>
</thead>
<tbody>
{events.map((user, idx) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default UserList;

import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import ProductDetails2 from './pages/ProductDetails2';
import UsersPage from './pages/User';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import axios from 'axios';
import { useFetcher } from 'react-router-dom';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
////////////////////////////////////////
id:"root",/////////////////////////
loader: async function () {
console.log("loader root >>>>>");
const response =await fetch("https://reqres.in/api/users?page=1");
const resData = await response.json();
return resData.data;
},
children: [
{ path: "/", element: <Home/> },
{ path: "/products", element: <Products/> },
{
path: "/users/",
element: <UsersPage/>,
id:"root2",
loader: async function () {
console.log("loader>>>>>");
try {
const response = await axios.get("https://reqres.in/api/users?page=2");
return response.data.data;
} catch (error) {
console.error("Error loading users:", error);
return [];
}
}
}, ////////////////추가
{ path: '/products/:productId', element: <ProductDetails/> }, ///////추가
{ path: '/products2', element: <ProductDetails2/> },
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
);
}
export default App;
import React from 'react';
import { useLoaderData, useRouteLoaderData } from 'react-router-dom';
function UserList() {
const events = useRouteLoaderData("root2");
if (!events || !events.length) {
return <div>No users available.</div>;
}
return (
<div>
<table border="1">
<thead>
<tr>
<th>아이디</th>
<th>이름</th>
<th>사진</th>
</tr>
</thead>
<tbody>
{events.map((user, idx) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default UserList;
개별컴포넌트에서loader함수작성하고export
import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import ProductDetails2 from './pages/ProductDetails2';
import UsersPage from './pages/User';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import axios from 'axios';
import { useFetcher } from 'react-router-dom';
import { loader as usersLoader } from './pages/User';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
////////////////////////////////////////
id:"root",/////////////////////////
loader: async function () {
console.log("loader root >>>>>");
const response =await fetch("https://reqres.in/api/users?page=1");
const resData = await response.json();
return resData.data;
},
children: [
{ path: "/", element: <Home/> },
{ path: "/products", element: <Products/> },
{
path: "/users/",
element: <UsersPage/>,
loader: usersLoader,
// loader: async function () {
// console.log("loader>>>>>");
// try {
// const response = await axios.get("https://reqres.in/api/users?page=2");
// return response.data.data;
// } catch (error) {
// console.error("Error loading users:", error);
// return [];
// }
// }
}, ////////////////추가
{ path: '/products/:productId', element: <ProductDetails/> }, ///////추가
{ path: '/products2', element: <ProductDetails2/> },
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
);
}
export default App;
useNavigation활용한사용자요청피드백제공
import React from 'react';
import UserList from '../components/UserList';
import { useLoaderData } from 'react-router-dom';
function UsersPage(props) {
const events = useLoaderData(); //App.js 의 데이터를 로드
return (
<div>
<h1>The Users Page</h1>
<UserList />
</div>
);
}
//app.js 에서 등록 사용
export async function loader(){
console.log("Users.lader 실행>>>>>");
const response = await fetch("https://reqres.in/api/users?page=2")
const resData = await response.json();
return resData.data;
}
export default UsersPage;
import React from 'react';
import { useLoaderData, useRouteLoaderData } from 'react-router-dom';
function UserList() {
const events = useLoaderData();
if (!events || !events.length) {
return <div>No users available.</div>;
}
return (
<div>
<table border="1">
<thead>
<tr>
<th>아이디</th>
<th>이름</th>
<th>사진</th>
</tr>
</thead>
<tbody>
{events.map((user, idx) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default UserList;

root.js
import React from 'react';
import { Outlet, useNavigation } from 'react-router-dom';
import MainNavigation from '../components/MainNavigation'
function Root(props) {
const navigation = useNavigation(); ///////////
return (
<div>
<MainNavigation/>
<hr/>
{/* {navigation.state === "loading" && <p>Loading...</p>} */}
{navigation.state === "loading" && alert("Loading...")}
{/*추가부분*/}
<Outlet/>
</div>
);
}
export default Root;

loader에서발생된예외처리
import axios from "axios";
export async function fetchUserList(){
let resData;
// try{
// //데이터 요청 응답 수신
// const response = await axios({
// url: "https://reqres.in/api/users?page=2",
// //method:"GET" //정상요청
// method:"GET" //정상요청
// //에러 실습은 PUT 으로 변경해서 테스트 할것
// });
// resData = await response.data.data;
// }catch(error){
// console.log(error);
// throw new Error(" 목록 로딩시 발생");
// }
//1.
// await axios({
// method: "get",
// url: "https://reqres.in/api/users?page=2",
// }).then(
// (res) => {
// console.log(">>>>>>",res);
// resData= res.data.data;
// }
// ).catch(
// (error) => {
// console.log(error);
// throw new Error("목록 로딩시 발생")
// }
// )
//2.
await axios.get(
"https://reqres.in/api/users?page=2"
).then(
(res) => {
console.log(">>>>>>",res);
resData= res.data.data;
}
).catch(
(error) => {
console.log(error);
throw new Error("목록 로딩시 발생")
}
)
return resData;
}
export async function insertUser(user){
let resData;
try{
const response = await axios({
method: "POST",
body: JSON.stringify(user),
headers: {
"Content-type" : "application/json",
},
url:"https://reqres.in/api/users"
})
resData = response.data.data;
}catch(error){
console.log(error);
throw new Error ("회원 추가시 에러 발생");
}
return resData;
}
import React from 'react';
import Home from './pages/Home'
import Products from './pages/Products'
import Root from './pages/Root';
import Error from './pages/Error';
import ProductDetails from './pages/ProductDetails';
import ProductDetails2 from './pages/ProductDetails2';
import UsersPage from './pages/User';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import axios from 'axios';
import { useFetcher } from 'react-router-dom';
import { loader as usersLoader } from './pages/User';
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
errorElement: <Error/>, ///////////////// 추가
////////////////////////////////////////
id:"root",/////////////////////////
loader: async function () {
console.log("loader root >>>>>");
//const response =await fetch("https://reqres.in/api/users?page=1");
const response =await fetch("https://r.in/api/users?page=1"); //error
const resData = await response.json();
return resData.data;
},
children: [
{ path: "/", element: <Home/> },
{ path: "/products", element: <Products/> },
{
path: "/users/",
element: <UsersPage/>,
loader: usersLoader, //error occur
// loader: async function () {
// console.log("loader>>>>>");
// try {
// const response = await axios.get("https://reqres.in/api/users?page=2");
// return response.data.data;
// } catch (error) {
// console.error("Error loading users:", error);
// return [];
// }
// }
}, ////////////////추가
{ path: '/products/:productId', element: <ProductDetails/> }, ///////추가
{ path: '/products2', element: <ProductDetails2/> },
]
},
]);
function App(props) {
return (
<>
<RouterProvider router={router}/>
</>
);
}
export default App;
import React from 'react';
import UserList from '../components/UserList';
import { useLoaderData } from 'react-router-dom';
import { json } from 'react-router-dom'; ///////////////////////
function UsersPage(props) {
const events = useLoaderData(); //App.js 의 데이터를 로드
return (
<div>
<h1>The Users Page</h1>
<UserList />
</div>
);
}
//app.js 에서 등록 사용
export async function loader(){
try{
console.log("Users.lader 실행>>>>>");
const response = await fetch("https://reqres.in/api/users?page=2")
const resData = await response.json();
return resData.data;
}catch(error){
console.log("catch error", error);
////////////////////////////// 추가
throw json({message: "could not fetch users" , status: 500})// import
//error.js 수정 useRouter() 로 사용중
}
}
export default UsersPage;
import React from 'react';
import MainNavigation from '../components/MainNavigation';
import { useRouteError } from 'react-router-dom';
function Error(props) {
const error = useRouteError();
console.log("error>>>>", error);
let title = "An error occured!!";
let message = "Something went wrong!!";
if (error && error.data && error.data.status === 500) {
message = error.data.message;
}
if (error && error.data && error.data.status === 404) {
title = "Not Found!!";
message = "Could not find resource or page";
}
return (
<div>
<MainNavigation />
<hr />
<h1>{title}</h1>
<p>{message}</p>
</div>
);
}
export default Error;

loader() 함수를 활용하여 컴포넌트가 생성되기 전에 필요한 데이터를 얻을 수 있듯이
action() 함수를 활용하면 태그의 데이터를 서버에 전송할 수 있다.
이때 폼은 리액트에서 제공한 이어야 되고 post로 지정해야 된다.
요청한 폼 데이터는 action({request}) 의 request.forData() 로 얻을 수 있다.
'Daily Codig Reminder' 카테고리의 다른 글
Node.js (0) | 2024.03.28 |
---|---|
css, routing, form (0) | 2024.03.24 |
axios, router (0) | 2024.03.24 |
useEffect , memo (0) | 2024.03.19 |
useRef (0) | 2024.03.19 |