23/12/21 next.js 기초복습

2023. 12. 22. 08:43카테고리 없음

 

 

next.js13버전이다. app-router 형식이다.

router방식이 프레임 워크에 내장 되어 있어 따로 react-router-dom 과 같은것들의

추가가 필요없다. 

src/app.폴더의 layout.jsx가 브라우저의 가장 외곽 라인을 형성하고

app폴더의 page.jsx가 layout 안쪽에 위치하게 된다.

 

src/app 폴더의 하위폴더의 폴더명은 곧 그안에 있는 page.jsx의 주소값이 된다.

폴더명이 create라면 그 밑의 파일인 page.jsx의 주소는 http://localhost:3000/create  가 된다. 

create의 폴더안에 layout.jsx가 존재 한다면 최상단 app/폴더의 layout 밑에 create layout 밑에 page가 존재하게 된다.

 

 

 

넥스트 js의 장점은 서버 사이드 랜더링이기 때문에 seo 에 좋다.

서버사이드랜더링 형식인 서버 컴포넌트들은 빠르게 랜더링되어

ux가 좋다고 한다. 

클라이언트사이드랜더링 형식인 클라이언트 컴포넌트들은

클라이언트들과 상호작용이 가능하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<layout.jsx> 최상단 src/app 폴더의 layout

import Link from "next/link";   // Link 태그이다. a태그의 상위판으로 a태그와 다르게 SPA를 제공한다.
import "./globals.css";          // 이 파일의 글로벌 css가 적용된다.
import axios from "axios";
import Control from "./Control";         //요건 따로 만든 컴포넌트
// import styled from "styled-components";

export const metadata = {
  title: "한지우!",
  description: "이몸",
};

export default async function RootLayout({ children }) {
  let res = await axios.get("http://localhost:4000/topics", {
    cache: {
      maxAge: 0, // 캐시 최대 기간을 0으로 설정하여 브라우저 캐시를 사용하지 않음
    },                                    //변경시 따르게 적용되도록 캐시가 안쌓이게 작업했는데 동작을 안함 ㅜㅜ
  });
  const topics = res.data;   //axios로 가져온 값을 담음

  return (
    <html>
      <body>
        <h1>
          <Link href="/">여기가 가장 상단 레이아웃</Link>  // 클릭시 홈으로 이동하게 함
        </h1>
        <ol>
          {/* <li>
            <Link href="/read/1">html</Link>
          </li>

          <li>
            <Link href="/read/2"> css</Link>
          </li> */}
          {topics?.map((item) => {
            return (
              <li key={item.id}>
                {" "}
                <Link href={`/read/${item.id}`}>{item.title}</Link>  // 맵함수를 돌려서 topic들을 뿌려주고
              </li>                                                   //클릭시 해당 params를 갖는 페이지로 이동시킴
            );
          })}
        </ol>
        {children}     //요게 중요한데 //여기 처음 layout 컴포넌트에 파라미터를 보면 props를 받음
        <Control />                                            //그프롭스의 칠드런을 이렇게 세팅하는데
        <h3>여기에 푸터 두면 되겄네</h3>      //이게 밑에 하위 페이지들이 놓일 자리가 됨 
      </body>
    </html>
  );
}

// const Body = styled.body`
//   background-color: lightblue;
// `;

 

<page.jsx> 최상의 page인 홈이다.

import Image from "next/image";
import Link from "next/link";
import ButtonPage from "./Button";    // 버튼페이지는 테스트용으로 만든거라 무시하겠다

export default function Home() {
  return (
    <>
      <h1>여긴 홈이야</h1>
      <div>헬로우 넥스트?</div>
      <ButtonPage />
      <img src="/피카츄.jpg" />엌 ㅋㅋㅋ 피카츄
    </>
  );
}          //별거 없다.

 

<page.js> read/[id]  폴더의 페이지이다. 폴더명은 곧 주소값이 된다고 했는데 [id]이렇게 해놓으면

주소값에 그 아이디를 갖는다고 한다.

import axios from "axios";
import React from "react";

export default async function Read(props) {
  const res = await axios.get(
    `http://localhost:4000/topics/${props.params.id}`,  // 요기가 신박한다. 일단 이 페이지는 서버컴포넌트라서
    {                                                                          //훅 사용이 제한된다. 그런데 이폴더는 주소에 아이디를 
      cache: {                                                             //갖는 폴더이다.
        maxAge: 0,                                             //그렇기 때문에 props안에 parms안에는 id값이 들어있다 오우
      },                                                    //고 아이디에 해당하는 topic하나의 정보를 가져온다.
    }
  );
  const topic = res.data;

  return (
    <>
      <div>{topic.title}</div>           //그리고 뿌린다.
      <div>{topic.content}</div>
    </>
  );
}

 

 

<page.jsx> create 폴더안에 page이다 

"use client";        //생성되는 컴포넌트는 기본적으로 서버컴포넌트인데 요거 써주면
                                         //클라이언트 컴포넌트가 된다. 
import axios from "axios";
import { useRouter } from "next/navigation";   // 유즈라우터 라고 useNavigate와 사용법이 비슷하다.
import React from "react";                             //넥스트 13버전 이후는 next/router 가 아니라 next/navigation
                                                                       //으로부터 임포트 받아야한다고 한다. 짜증
export default function Create() {
  const router = useRouter();
  const onSubmitHandler = async (e) => {
    e.preventDefault();
    const title = e.target.title.value;
    const content = e.target.content.value;    //폼태그 하위에 있는 애들의 네임값이 title인놈과 content인놈의벨류
    const postTopic = await axios.post("http://localhost:4000/topics", {
      title,
      content,                                      //타이틀과 컨텐트를 제이슨서버로 투척
    });
    const lastId = postTopic.data.id;
    router.refresh();                        //요게 라우터를 랜더링 시킨다고한다.
    router.push(`read/${lastId}`); //요게 라우터 이동법인데 뒤에 저 주소값으로 보냄
  };

  return (
    <>
      <form onSubmit={onSubmitHandler}>
        <div>
          <span>타이틀 :</span> <input name="title" />
        </div>
        <div>
          <span> 내용 :</span> <textarea name="content" />
        </div>
        <div>
          <input type="submit" value="생성" />
        </div>
      </form>
    </>
  );
}

 

<page.jsx> update.[id] 폴더의 페이지 이다.

"use client";

import axios from "axios";
import { useParams, useRouter } from "next/navigation";  // 훅이나 온클릭같은 클라이언트 상호작용
import React, { useEffect, useState } from "react";             //하는 것들은 클라이언트 컴포넌트에서만 사용가능

export default function Update() {
  const [topic, setTopic] = useState({ title: null, content: null }); //제이슨에서 받아온정보 저장할 유즈스테이트
  const router = useRouter();
  const params = useParams();
  useEffect(() => {
    const getInfo = async () => {
      const res = await axios.get("http://localhost:4000/topics/" + params.id);  //해당 아이디와 일치하는 topic가져오고
      const { title, content } = res.data;     //거기에 title content 뽑고
      setTopic({ title, content });  스테이트에 저장하고
    };
    getInfo();          //유즈이펙트로 일회만 함수 실행하고 유즈 이펙트에 [] 빼뜨려서 제이슨 계속 겟하고 난리남 ㅋㅋ
  }, []);                      //조심해야겄음
  const onSubmitHandler = async (e) => {
    e.preventDefault();
    const title = e.target.title.value;
    const content = e.target.content.value;
    const postTopic = await axios.patch(             //수정 로직 patch매서드 써서 유즈 파람스로 가져온 id와
      "http://localhost:4000/topics/" + params.id,       //일치하는 놈수정
      {
        title,                                                              //요때 타이틀은 인풋값들에서 가져옴
        content,
      }
    );
    const lastId = postTopic.data.id;           //로직끝나고 해당read페이지로 이동하기 위한 작업
    router.refresh();
    router.push(`../read/${lastId}`);       //요거쓰면 이동
  };

  return (
    <>
      <form onSubmit={onSubmitHandler}>
        <div>
          <span>타이틀 :</span>{" "}
          <input
            name="title"
            value={topic.title}
            onChange={(e) => {
              setTopic({ ...topic, title: e.target.value });   //
            }}
          />
        </div>
        <div>
          <span> 내용 :</span>{" "}
          <textarea
            name="content"
            value={topic.content}
            onChange={(e) => {
              setTopic({ ...topic, content: e.target.value });
            }}
          />
        </div>
        <div>
          <input type="submit" value="생성" />
        </div>
      </form>
    </>
  );
}

 

<Control.jsx> 최상단 레이아웃을 보면 Control 태그가 있다.

"use client";
import axios from "axios";
import Link from "next/link";
import { useParams } from "next/navigation";
import { useRouter } from "next/navigation";

export default function Control() {
  const params = useParams();             //layout 페이지는 서버사이드 랜더링의 장점을 위해
  const id = params.id;                        //서버컴포넌트로 놔뒀는데 그안에 이 아이는 유저와의 상호작용이
  const router = useRouter();                 //필요하여 새로 파일로 분리하고 클라이언트 컴포넌트화했다. 귀찮
                                                                     //그냥 리액트가 편해 ㅜㅜ
  const onDeleteHandeler = async () => {
    await axios.delete("http://localhost:4000/topics/" + id);
    router.push("/");                         //단순로직 유즈파람스로 가져온 아이디에 해당하는 애 지우고 홈으로 이동
  };
  return (
    <>
      <ul>
        <li>
          <Link href="/create">크리에이트</Link>
        </li>
        {id && (                //아이디가 있는 페이지 에서만 밑에 태그들이 랜더링 됨
          <>
            <li>
              <Link href={`/update/${id}`}>업데이트</Link>
            </li>

            <input type="button" value="delete" onClick={onDeleteHandeler} />    //그걸 실행하는 버튼
          </>
        )}
      </ul>
    </>
  );
}

//일단 기본기 연습을 해봤는데 이거 끝나고 리덕스 툴킷을 넥스트에 적용시킬려고 죽쑤고 있고

//다하니까 이젠 다른거에 또 에러나고 next 어렵다..