Routing_loader

2024. 3. 24. 16:27Daily 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