[React] chapter_09

DEVELOPERS_Ivan ㅣ 2023. 9. 1. 20:00

./public/index.html
부트스트랩 js cdn : 드롭다운 메뉴들 사용 코드 추가

./pages/index.js
메뉴 라이브러리 import

./components/Header.js
부트스트랩 코드를 이용하여 공통 머리말에 드롭다운 메뉴 설정 공통 컴포넌트
./components/NotFound.js
(불법 접근 또는 url 없는 주소 접근) 공통 컴포넌트

./utils/http-common.js
가짜 백엔드에 주소 데이터 접근

license.txt
라이센스
더보기
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
    <!-- TODO : 부트스트랩 css 삽입 bootstrap css cdn -->
    <link
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
    <!-- TODO : 부트스트랩 js cdn : 드롭다운 메뉴들 사용 -->
    <script
      integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
      crossorigin="anonymous"
    ></script>
  </body>
</html>
더보기
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// TODO: 메뉴 라이브러리 import
import { BrowserRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
더보기
// TODO : 공통 컴포넌트 ./components/Header.js
// TODO : 부트스트랩 코드를 이용하여 공통 머리말에 드롭다운 메뉴 설정해보기

// TODO : .../009/01_axios/public/index.html 파일에서 부트스트랩 js cdn : 드롭다운 메뉴들 사용 코드 삽입
// TODO : React 컴포넌트
// 단축키 : rfce

import React from "react";
import { Link } from "react-router-dom"; // 메뉴 라이브러리

function Header() {
  return (
    <div>
      {/* 부트스트랩 메뉴 추가 */}
      <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container-fluid">
          {/* 메뉴 제목 시작 */}
          {/* TODO: a class="navbar-brand" href="#" link to로 변경 */}
          <Link to="/" class="navbar-brand">
            Simple DMS
          </Link>
          {/* 메뉴 제목 끝 */}
          <button
            class="navbar-toggler"
            type="button"
            data-bs-toggle="collapse"
            data-bs-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span class="navbar-toggler-icon"></span>
          </button>
          {/* 아래 : 메뉴 등록 부분 시작 */}
          <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
              {/* dept 메뉴 시작 */}
              <li class="nav-item dropdown">
                {/* 대메뉴 시작 */}
                <a
                  class="nav-link dropdown-toggle"
                  href="#"
                  id="navbarDropdown"
                  role="button"
                  data-bs-toggle="dropdown"
                  aria-expanded="false"
                >
                  Dept
                </a>
                {/* 대메뉴 끝 */}

                {/* 소메뉴 시작 */}
                <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                  <li>
                    <Link to="/dept" class="dropdown-item">
                      Dept
                    </Link>
                  </li>
                  <li>
                    <Link to="/add-dept" class="dropdown-item">
                      Add Dept
                    </Link>
                  </li>
                </ul>
                {/* 소메뉴 끝 */}
              </li>
              {/* dept 메뉴 끝 */}

              {/* emp 메뉴 시작 */}
              <li class="nav-item dropdown">
                {/* 대메뉴 시작 */}
                <a
                  class="nav-link dropdown-toggle"
                  href="#"
                  id="navbarDropdown"
                  role="button"
                  data-bs-toggle="dropdown"
                  aria-expanded="false"
                >
                  Emp
                </a>
                {/* 대메뉴 끝 */}

                {/* 소메뉴 시작 */}
                <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                  <li>
                    <Link to="/emp" class="dropdown-item">
                      Emp
                    </Link>
                  </li>
                  <li>
                    <Link to="/add-emp" class="dropdown-item">
                      Add Emp
                    </Link>
                  </li>
                </ul>
                {/* 소메뉴 끝 */}
              </li>
              {/* emp 메뉴 끝 */}
            </ul>
          </div>
          {/* 메뉴 등록 부분 끝 */}
        </div>
      </nav>
    </div>
  );
}

export default Header;
더보기
// TODO : 공통 컴포넌트 ./components/NotFound.js (불법 접근 또는 url 없는 주소 접근)
// TODO : 불법 접근 또는 url 없는 주소창 주소 접근 설정

// TODO : React 컴포넌트
// 단축키 : rfce
import React from "react";

function NotFound() {
  return (
    <div>
      {/* 접근이 안되는 url를 입력하면 아래 문장이 뜬다. */}
      <h1>웹 페이지 주소를 잘못 입력하셨습니다.</h1>
    </div>
  );
}

export default NotFound;
더보기
// TODO : http-common.js
// TODO : 가짜 백엔드에 주소 데이터 접근하는 방법

// 백엔스 기본 url 주소 설정(axios 사용)
// 가짜 백엔드(json-sver) : http://localhost:8000
// 자원(resource) url : /dept
// 사용 예) http://localhost:8000/dept
// 이 파일에서는 기본주소만 설정하고 : http://localhost:8000
// 다른 파일에서 추가 url 설정 : /dept

// 1) 통신 라이브러리 추가 : import
import axios from "axios";

// 2) 기본 주소 설정 : 가짜 백엔드(http://localhost:8000)
export default axios.create({
  baseURL: "http://localhost:8000", // 기본주소
  headers: {
    "Content-Type": "application/json", // 통신에 사용할 문서종류(json)
  },
});
더보기

The MIT License

Copyright (c) <year> <copyright holders>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

License.txt 경로


App.js
01_dept( Dept.js, AddDept.js DeptList.js)
02_json_server

네비게이션 바를 이용한 상단 메뉴와 드롭다운 메뉴 만들고 상세 조회페이지 조회 및 수정
더보기
// TODO : 부모 컴포넌트 메인 : App.js

// TODO : App.css import (기본 : 중앙정렬)
import "./App.css";

// TODO : 메뉴 라이브러리 가져오기(import)
import { Routes, Route } from "react-router-dom";

// TODO : 공통 컴포넌트 가져오기(import)
import Header from "./components/Header";
import NotFound from "./components/NotFound";

// TODO : 페이지 컴포넌트 가져오기(import)
import Home from "./pages/Home";

// TODO : 페이지 컴포넌트 자식 가져오기(부서메뉴)
import DeptList from "./pages/dept/DeptList";
import AddDept from "./pages/dept/AddDept";
import Dept from "./pages/dept/Dept";

// TODO : 연습) 페이지 컴퍼넌트 자식 가져오기(사원메뉴)
import EmpList from "./pages/emp/EmpList";
import AddEmp from "./pages/emp/AddEmp";
import Emp from "./pages/emp/Emp";



function App() {
  return (
    <div className="App">
      {/* TODO : 컴포넌트와 메뉴 url 연결 : 라우팅(Router) */}
      <Header />

      {/* 본문 : 라우팅 설정 */}
      <div className="container mt-3">
        <Routes>
          {/* 1st 페이지 : / */}
          <Route path="/" element={<Home />} />.
          {/*  * : 지정되지 않은 모든 url  */}
          <Route path="*" element={<NotFound />} />
          {/* TODO: 부서메뉴 */}
          <Route path="/dept" element={<DeptList />} />
          <Route path="/add-dept" element={<AddDept />} />
          <Route path="/dept/:id" element={<Dept />} />
          {/* TODO: 연습) 사원메뉴 */}
          <Route path="/emp" element={<EmpList />} />
          <Route path="/add-emp" element={<AddEmp />} />
          <Route path="/emp/:id" element={<Emp />} />
        </Routes>
      </div>
    </div>
  );
}

export default App;
더보기
// TODO : 자식 컴포넌트 ./pages/dept/Dept.js
// TODO : dept 상세조회 페이지(수정/삭제)

// TODO : import 메뉴 라이브러리
import { useParams, useNavigate } from "react-router-dom";

// TODO : import axios 공통 함수 파일
import DeptService from "../../services/DeptService";

// TODO : React 컴포넌트
import React, { useEffect, useState } from "react";
// 단축키 : rfce

function Dept() {
  // TODO : 변수 정의
  // TODO :이전 페이지에서 변수의(id) 값을(부서번호) 전송 : 받기
  const { id } = useParams(); // 전송된 값 받기 함수 호출
  let navigate = useNavigate(); // 페이지 강제 이동시키는 함수

  // TODO : 바인딩 변수
  // 임시 객체(초기화)
  const ininialDept = {
    id: "", // 부서번호
    dname: "", // 부서명
    loc: "", // 부서위치
  };

  // 바인딩 변수 사용법 : let [변수명, set변수명] = useState(초기값);
  let [dept, setDept] = useState(ininialDept); // 백엔드로 전송할 변수(insert 요청)
  let [message, setMessage] = useState(""); // 수정버튼 클릭 후 성공여부 메세지 변수

  // TODO : 함수 정의
  // TODO : 최초 화면이 뜰때 부서번호에 해당하는 데이터를 화면에 표시하는 함수
  // TODO : 백엔드에 부서번호에 해당되는 부서객체를 조회 요청(1건 리턴)
  // TODO : axios 함수 : get(`/dept/${id}`) 함수 [vs 저장요청 : post()]

  // TODO : 1건 조회 함수(상세조회 함수) 정의
  const getDept = (id) => {
    DeptService.get(id) // 상세조회 요청(id)
      .then((response) => {
        // 성공시 자동실행
        setDept(response.data); // 백엔드에서 보내준 결과 저장
        // 로그 찍기
        console.log(response.data);
      })
      .catch((e) => {
        // 실패시 자동실행
        console.log(e); // 에러메세지 출력
      });
  };

  // TODO : 화면이 뜰떄 실행되는 함수
  // TODO : 화면이 뜰떄 실행되는 함수 + id 값이 수정되었을때도 자동실행
  // 사용법(수정) : useEffect(()=>{실행문}, [감시할변수명]);
  useEffect(() => {
    if (id) {
      getDept(id); // 상세조회 함수 실행
    }
  }, [id]);

  // TODO : 역바인딩 함수 정의
  const handleInputChange = (event) => {
    let attrValue = event.target.value; // 화면 입력값
    let attrName = event.target.name; // 화면 태그 이름(===객체의 속성명)
    //스프레드 연산자로 속성의 값을 수정
    setDept({ ...dept, [attrName]: attrValue });
  };

  // TODO: 수정함수 정의 : 클릭
  // axios 공통함수 : axios.put("url/부서번호", 수정될객체)
  const updateDept = () => {
    DeptService.update(dept.id, dept) // 수정 요청(부서번호(id), 부서객체(dept))
      .then((response) => {
        // 성공시 자동실행
        // 로그 찍기
        console.log(response.data);
        // TODO : 수정 성공시 화면에 수정 성공 메세지를 출력
        setMessage("부서 수정이 성공하였습니다.");
      })
      .catch((e) => {
        // 실패시 자동실행
        console.log(e); // 에러메세지 출력
      });
  };

  // TODO : 삭제함수 정의 : 클릭
  // axios 공통함수 : axios.delete(url/부서번호(id))
  // 지정한 키워드를 주어 해당 url만 삭제시킨다. 지정 키워드를 안주면 전체 삭제가된다.
  const deleteDept = () => {
    DeptService.remove(dept.id) // 삭제 요청(id)
      .then((response) => {
        // 로그 찍기
        console.log(response.data);
        // TODO : 삭제 성공 후 자동으로 1st 페이지로 이동(전체 조회페이지)
        // 사용법 : navigate("이동될페이지주소")
        navigate("/dept"); // TODO : 강제페이지 이동 함수 실행
      })
      .catch((e) => {
        // 실패시 자동실행
        console.log(e); // 에러메세지 출력
      });
  };

  return (
    // TODO : html 정의
    <>
      {/* 제목 start */}
      <div className="row">
        {/* 제목 시작 */}
        <div className="col-md-6 mb-5 mt-5">
          <h1>Dept Detail No Page</h1>
        </div>
        {/* 제목 끝 */}
      </div>
      {/* 제목 end */}

      <>
        {dept ? (
          /* 상세화면 form 시작 */
          <div className="col-6 mx-auto">
            <form>
              {/* 부서명(dname) 시작 */}
              <div className="row g-3 align-items-center mb-3">
                <div className="col-3">
                  <label htmlFor="dname" className="col-form-label">
                    Dname
                  </label>
                </div>
                <div className="col-9">
                  <input
                    type="text"
                    id="dname"
                    required
                    className="form-control"
                    value={dept.dname}
                    onChange={handleInputChange}
                    placeholder="dname"
                    name="dname"
                  />
                </div>
              </div>
              {/* 부서명 끝 */}

              {/* 부서위치(loc) 시작 */}
              <div className="row g-3 align-items-center mb-3">
                <div className="col-3">
                  <label htmlFor="loc" className="col-form-label">
                    Loc
                  </label>
                </div>

                <div className="col-9">
                  <input
                    type="text"
                    id="loc"
                    required
                    className="form-control"
                    value={dept.loc}
                    onChange={handleInputChange}
                    placeholder="loc"
                    name="loc"
                  />
                </div>
              </div>
              {/* 부서위치(loc) 끝 */}
            </form>

            {/* 버튼 시작 : 삭제 / 수정 버튼 */}
            <div className="row g-3 mt-3 mb-3">
              <button
                onClick={deleteDept}
                className="btn btn-outline-danger ms-3 col"
              >
                Delete
              </button>

              <button
                type="submit"
                onClick={updateDept}
                className="btn btn-outline-success ms-2 col"
              >
                Update
              </button>
            </div>
            {/* 버튼 끝 : 삭제 / 수정 버튼 */}

            {/* 수정버튼을 클릭해서 성공하면 성공/실패메세지 출력 */}
            <p>{message}</p>
          </div>
        ) : (
          /* 상세화면 form 끝 */
          /* 에러시 보여줄 화면 시작 */
          <div className="col-6 mx-auto">
            <br />
            <p>Please click on a Dept...</p>
          </div>
          /* 에러시 보여줄 화면 끝 */
        )}
      </>
    </>
  );
}

export default Dept;
더보기
// TODO : 자식 컴포넌트 ./pages/dept/AddDept.js
// TODO : // dept 추가페이지

// TODO : React 컴포넌트
// 단축키 : rfce
import React, { useState } from "react";
import DeptService from "../../services/DeptService";

function AddDept() {
  // TODO: 변수 정의
  // 임시 객체(초기화)
  const ininialDept = {
    id: null, // 부서번호
    dname: "", // 부서명
    loc: "", // 부서위치
  };
  // 바인딩 변수 사용법 : let [변수명, set변수명] = useState(초기값);
  let [dept, setDept] = useState(ininialDept); // 백엔드로 전송할 변수(insert 요청)
  let [submitted, setSubmitted] = useState(false); // 저장버튼 클릭 여부를 가진 변수

  // TODO: 역바인딩 함수 정의
  // 역바인딩 함수 버튼 사용법 : onChange={함수명}
  // nfn : 화살표 단축키 사용 :
  // const onChange함수명 = (event) => { let  }
  // const handleInputChange = (event) => {     let attrValue = event.target.value; // 화면 입력값
  // let attrName = event.target.value; // 화면 태그 이름(===객체의 속성명)}
  //스프레드 연산자로 속성의 값을 수정
  // setDept({...dept, [attrName]:attrValue});

  const handleInputChange = (event) => {
    let attrValue = event.target.value; // 화면 입력값
    let attrName = event.target.name; // 화면 태그 이름(===객체의 속성명)
    //스프레드 연산자로 속성의 값을 수정
    setDept({ ...dept, [attrName]: attrValue });
  };

  // TODO: 저장 함수 정의 : 클릭 함수(onClick={함수명})
  // nfn : 화살표 단축키 사용 :
  // 백엔드로 dept 객체를 저장 요청 (axios : 공통저장함수(caeate()) )
  // const onChange함수명 = (second) => { third }
  const saveDept = () => {
    // 임시 저장용 객체
    let data = {
      dname: dept.dname, // 화면 입력값(부서명)
      loc: dept.loc, // 화면 입력값(부서위치)
    };

    // TODO: 화면전환 함수 정의
    DeptService.create(data) // 저장 요청(부서객체)
      .then((response) => {
        setDept(response.data); // 백엔드에 저장된 객체를 받아서 변수에 저장
        setSubmitted(true); // 저장 버튼 클릭 + 저장성공(자동실행)(false -> true)
        // 로그 찍기
        console.log(response.data);
      })
      .catch((e) => {
        // 실패하면 자동실행
        console.log(e); // 에러 메시지 출력
      });
  };

  // 저장 버튼 클릭 : 새로운 화면 전환(버튼이 1개 있는 화면)
  // 3항 연산자의 다른 화면이 출력(submitted == true)
  // nfn : 화살표 단축키 사용
  const newDept = (newept) => {
    // 역할 : 변수 초기화(객체, setSubmitted = false)
    setDept(ininialDept);
    setSubmitted(false);
  };

  return (
    // TODO : html 정의
    <div className="row">
      {/* 변수(submitted)? 참 : 거짓 */}
      {submitted ? (
        // submitted = true : 저장버튼을 클릭했다는 의미
        // newDept() 함수 실행되면 : 새로운 빈폼을 화면에 보여주고, submitted = false
        <div className="col-6 mx-auto">
          <h4>You submitted successfully!</h4>
          <button className="btn btn-success" onClick={newDept}>
            Add
          </button>
        </div>
      ) : (
        // TODO: <></> : 플래그멘테이션(flagmetation)
        // TODO: ex) 중복 태그가 많을 떄 간소화시킬 수 있음
        <>
          {/* 제목 시작 */}
          <div className="row">
            {/* 제목 시작 */}
            <div className="col-md-6 mb-5 mt-5">
              <h1>Add Dept</h1>
            </div>
            {/* 제목 끝 */}
          </div>
          {/* 제목 끝 */}

          {/* 폼(form) 입력양식 시작 */}
          <div className="col-6 mx-auto">
            {/* 부서명(dname) 시작 */}
            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="dname" className="col-form-label">
                  Dname
                </label>
              </div>

              <div className="col-9">
                <input
                  type="text"
                  id="dname"
                  required
                  className="form-control"
                  value={dept.dname}
                  onChange={handleInputChange}
                  placeholder="dname"
                  name="dname"
                />
              </div>
            </div>
            {/* 부서명 끝 */}

            {/* 부서위치(loc) 시작 */}
            <div className="row g-3 align-items-center mb-3">
              <div className="col-3">
                <label htmlFor="loc" className="col-form-label">
                  Loc
                </label>
              </div>
              <div className="col-9">
                <input
                  type="text"
                  id="loc"
                  required
                  className="form-control"
                  value={dept.loc}
                  onChange={handleInputChange}
                  placeholder="loc"
                  name="loc"
                />
              </div>
            </div>
            {/* 부서위치 끝 */}

            {/* 저장 버튼 시작 */}
            <div className="row g-3 mt-3 mb-3">
              <button
                onClick={saveDept}
                className="btn btn-outline-primary ms-2 col"
              >
                Submit
              </button>
            </div>
            {/* 저장 버튼 끝 */}
          </div>
          {/* 폼(form) 입력양식 끝 */}
        </>
      )}
    </div>
  );
}

export default AddDept;
더보기
// TODO : 자식 컴포넌트 ./pages/dept/DeptList.js
// TODO : dept 조회페이지

// TODO: import 메뉴 라이브러리
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";

// TODO: import axios 공통 함수 파일
import DeptService from "../../services/DeptService";

// TODO : import React 컴포넌트
// 단축키 : rfce
function DeptList() {
  // TODO : 변수 정의
  let [dept, setDept] = useState([]); // 벡엔드 부서 데이터를(객체배열) 받을 변수
  let [searchDname, setSearchDname] = useState(""); // 검색어 변수

  // TODO : 함수 정의
  // nfn : 화살표 단축키
  // 벡엔드 모든 데이터 조회 함수 : axis 사용
  const retrieveDept = () => {
    // axios 함수 : get() 요청 : (js 공통 함수를 만들고 공통함수명으로 호출)
    // .then() : 성공(자동실행)
    // .catch() : 실패(자동실행)

    DeptService.getAll() // 벡엔드 요청
      // 성공 자동실행
      .then((response) => {
        setDept(response.data); // TODO: 실질적인 벡엔드 데이터 저장(response.data)
        // TODO: 백엔드에서 전달해준 데이터를 저장
        console.log(response.data); // 성공 로그찍기
      })
      // 실패 자동실행
      .catch((e) => {
        // 실패 자동실행
        console.log(e); // 에러메세지 콘솔로 출력
      });
  };

  //  화면이 뜰때 retrieveDept 실행
  // useEffect(()=>{실행문}, []);
  useEffect(() => {
    retrieveDept(); // 함수의 사용
  }, []);

  // TODO: 검색어 조회 함수 : findByDname()
  // nfn : 화살표 단축키
  // axios : get(url) : 공통함수 : DeptService.findByDname(검색어)
  const findByDname = () => {
    DeptService.findByDname(searchDname) // 검색어로 조회 요청
      .then((response) => {
        // 성공하면 자동실행
        setDept(response.data); // 벡엔드에서 전달해준 데이터를(response.data) 저장
        // 로그 찍기
        console.log(response.data); // 벡엔드데이터(response.data)
      })
      .catch((e) => {
        // 실패하면 자동실행
        console.log(e); // 에러메세지 출력
      });
  };

  // TODO: 검색어 입력양식 : onChange={함수명}
  // 역바인딩 함수 : 코딩
  // nfn
  const onChangeSearchDname = (event) => {
    setSearchDname(event.target.value); // 역바인딩 코딩
  };

  return (
    // TODO : html 정의
    <div>
      <div className="row">
        {/* 제목 시작 */}
        <div className="col-md-12 mb-5 mt-5">
          <h1>Dept List</h1>
        </div>
        {/* 제목 끝 */}
      </div>

      {/* 검색창 시작 */}
      <div className="row mb-5 justify-content-center">
        {/* w-50 : 크기 조정, mx-auto : 중앙정렬(margin: 0 auto), justify-content-center */}
        <div className="col-12 w-50 input-group mb-3">
          {/* 검색어 입력창 시작 */}
          <input
            type="text"
            className="form-control"
            placeholder="Search by dname"
            value={searchDname}
            onChange={onChangeSearchDname}
          />
          {/* 검색어 입력창 끝 */}

          {/* 검색 버튼 시작 */}
          <div className="input-group-append">
            <button
              className="btn btn-outline-secondary"
              type="button"
              onClick={findByDname}
            >
              Search
            </button>
          </div>
          {/* 검색 버튼 끝 */}
        </div>
      </div>
      {/* 검색창 끝 */}

      {/* 테이블 시작 */}
      <div className="col-md-12">
        {/* 테이블 제목 시작 */}
        <table className="table">
          <thead className="table-light">
            <tr>
              <th scope="col">Dname</th>
              <th scope="col">Loc</th>
              <th scope="col">Actions</th>
            </tr>
          </thead>
          {/* 테이블 제목 끝 */}
          <tbody>
            {/* 반복문 시작 */}
            {dept &&
              dept.map((data, index) => (
                <tr key={index}>
                  <td>{data.dname}</td>
                  <td>{data.loc}</td>
                  <td>
                    {/* TODO: 1) 사용법 :/url?변수명=변수값 (쿼리스트링 방식)  */}
                    {/* TODO: 2) 사용법 :/url/변수값        (파라메터 방식)
                                  -> 다른페이지에서 값을 받을수 있음  */}
                    {/* 클릭하면 상세페이지가 화면에 뜸(부서번호도 넘겨줌) */}
                    <Link to={"/dept/" + data.id}>
                      <span className="badge bg-success">Edit</span>
                    </Link>
                  </td>
                </tr>
              ))}
            {/* 반복문 끝 */}
          </tbody>
        </table>
        {/* 반복문 끝 */}
      </div>
      {/* 테이블 끝 */}
    </div>
  );
}

export default DeptList;
더보기
 
  "dept": [
    {
      "id": 1,
      "dname": "부서명",
      "loc": "위치"
    },
    {
      "id": 2,
      "dname": "부서명 2",
      "loc": "위치 2"
    },
    {
      "id": 3,
      "dname": "부서명 3",
      "loc": "위치 3"
    }
  ]
}

json_server 백앤드 서버 db.json 기존 저장되어 있던 데이터
json_server 백앤드 서버 db.json 로 입력한 추가 데이터 전송
추가된 데이터 업데이트(수정) 및 삭제

 

'Visual Studio Code' 카테고리의 다른 글

[React&Typescipt] chapter_01 ~ 04  (0) 2023.09.06
[React] chapter_08  (0) 2023.09.01
[React] chapter_07  (0) 2023.09.01
[React] chapter_06  (0) 2023.08.31
[React] chapter_05  (0) 2023.08.31