엘리스 53일차 수요일 실시간 강의 react-router-dom

치즈말랑이·2022년 6월 15일
0

엘리스

목록 보기
45/47
post-thumbnail
post-custom-banner

이고잉님 강의

immutable : https://pks2974.medium.com/immutable-js-%EA%B0%84%EB%8B%A8%EC%A0%95%EB%A6%AC-bbd5ad20bbdf

react-router-dom : https://reactrouter.com/docs/en/v6/getting-started/overview

json-server 여는법: npx json-server --watch -p 3333 db.json

전체 코드

import logo from "./logo.svg";
import "./App.css";
import { useState, useEffect } from "react";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";
import styled from "styled-components";
import { Link, Routes, Route, useParams, useNavigate } from "react-router-dom";

function Header(props) {
  return (
    <header className={props.className}>
      <h1>
        <Link
          to="/"
          onClick={(evt) => {
            props.onSelect();
          }}
        >
          WWW
        </Link>
      </h1>
    </header>
  );
}
const HeaderStyled = styled(Header)`
  border-bottom: 1px solid gray;
  color: red;
`;
function Article(props) {
  return (
    <article>
      <h2>{props.title}</h2>
      {props.body}
    </article>
  );
}
function Nav(props) {
  const liTags = props.data.map((e) => {
    return (
      <li key={e.id}>
        <Link
          to={"/read/" + e.id}
          onClick={(evt) => {
            props.onSelect(e.id);
          }}
        >
          {e.title}
        </Link>
      </li>
    );
  });
  return (
    <nav>
      <ol>{liTags}</ol>
    </nav>
  );
}
function Create(props) {
  return (
    <article>
      <h2>Create</h2>
      <form
        onSubmit={(evt) => {
          evt.preventDefault();
          const title = evt.target.title.value;
          const body = evt.target.body.value;
          props.onCreate(title, body);
        }}
      >
        <p>
          <input type="text" name="title" placeholder="title"></input>
        </p>
        <p>
          <textarea name="body" placeholder="body"></textarea>
        </p>
        <p>
          <input type="submit" value="Create"></input>
        </p>
      </form>
    </article>
  );
}
function Read(props) {
  const params = useParams();
  const id = Number(params.topic_id);
  const [topic, setTopic] = useState({ title: null, body: null });
  useEffect(() => {
    (async () => {
      const resp = await fetch("http://localhost:3333/topics/" + id);
      const data = await resp.json();
      setTopic(data);
    })();
  }, [id]);
  return <Article title={topic.title} body={topic.body}></Article>;
}
function Control(props) {
  const params = useParams();
  const id = Number(params.topic_id);
  let contextUI = null;
  if (id) {
    contextUI = (
      <>
        <Button variant="outlined">Update</Button>
        <Button
          variant="outlined"
          onClick={() => {
            props.onDelete(id);
          }}
        >
          Delete
        </Button>
      </>
    );
  }
  return (
    <>
      <Button component={Link} to="/create" variant="outlined">
        Create
      </Button>
      {contextUI}
    </>
  );
}
function App() {
  const [mode, setMode] = useState("WELCOME"); // todo 삭제 예정
  const [id, setId] = useState(null); // todo 삭제 예정
  const [nextId, setNextId] = useState(3);
  const [topics, setTopics] = useState([
    { id: 1, title: "html", body: "html is ..." },
    { id: 2, title: "css", body: "css is ..." },
  ]);
  const refreshTopics = async () => {
    const resp = await fetch("http://localhost:3333/topics");
    const data = await resp.json();
    setTopics(data);
  };
  useEffect(() => {
    refreshTopics();
  }, []);
  const navigate = useNavigate();
  return (
    <div>
      <HeaderStyled onSelect={headerHandler()}></HeaderStyled>
      <Nav data={topics} onSelect={navHandler()}></Nav>
      <Routes>
        <Route
          path="/"
          element={<Article title="Welcome" body="Hello, WEB!"></Article>}
        ></Route>
        <Route
          path="/create"
          element={<Create onCreate={onCreateHandler}></Create>}
        ></Route>
        <Route
          path="/read/:topic_id"
          element={<Read topics={topics}></Read>}
        ></Route>
      </Routes>
      <Routes>
        {["/", "/read/:topic_id", "/update/:topic_id"].map((path) => {
          return (
            <Route
              key={path}
              path={path}
              element={
                <Control
                  onDelete={(id) => {
                    deleteHandler(id);
                  }}
                ></Control>
              }
            ></Route>
          );
        })}
      </Routes>
    </div>
  );
  async function onCreateHandler(title, body) {
    const resp = await fetch("http://localhost:3333/topics", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ title, body }),
    });
    const data = await resp.json();
    navigate(`/read/${data.id}`);
    refreshTopics();
  }

  function navHandler() {
    return (id) => {
      setMode("READ");
      setId(id);
    };
  }

  function deleteHandler(id) {
    const newTopics = topics.filter((e) => {
      if (e.id === id) {
        return false;
      } else {
        return true;
      }
    });
    setTopics(newTopics);
    navigate("/");
  }

  function createHandler() {
    return () => {
      setMode("CREATE");
    };
  }

  function headerHandler() {
    return () => {
      setMode("WELCOME");
    };
  }
}

export default App;

코치님 강의

import React, { useState, useEffect } from "react";
import axios from "axios";

function Users() {
  let [result, setResult] = useState("");
  // useEffect를 사용하지 않고 아래를 출력해보세요.
  console.log(result);

  // axios.get을 호출하고 result에 반환되는 데이터를 저장하세요.
   const axiosGet = async () => {
    try {
        const response = await axios.get('https://reqres.in/api/users/2');
        setResult(response.data.data);
    } catch(e) {console.log(e)}
   }
    
    useEffect(() => {
        axiosGet();
    })
//     then-catch 사용, 정상 작동
//     useEffect(() => {
//     axios.get("https://reqres.in/api/users/2")
//         .then(res => setResult(res.data.data));
//     }, []);
    
//     잘못된 예 1
//     useEffect(async () => {
//     try{
//         const result = await axios.get('https://reqres.in/api/users/2');
//         setResult(result.data.data);
//     } catch(err) {
//         console.log(err);
//     }
//   }, [])
  
//     잘못된 예 2
//     useEffect(() => {
//     axios.get("https://reqres.in/api/users/2")
//         .then(res => setResult(res.data.data));
//     });
  return (
    <div>
      <h4>React Axios로 HTTP GET 요청하기</h4>
      <div>
        {/* result를 이용해 출력 결과와 동일하게 출력하세요. */}
        <p>Name: {result.first_name} {result.last_name}</p>
        <p>Email: {result.email}</p>
        
      </div>
    </div>
  );
}

export default Users;

axios는 비동기적 함수이므로 then catch 혹은 async await를 사용해야 한다.
그런데 만약 useEffect의 두번째인자에 []를 주지 않는다면, 무한루프에 빠져 계속 렌더링 한다.
맨 처음 setResult에 data를 담으면 state가 바껴서 페이지를 다시 렌더링 하고, 그러면 axios가 다시 호출되고, 그러면 다시 setResult를 건든다. 그래서 두번째인자에 []를 줘서 처음렌더링됐을때 한번만 data를 불러오게 한다.

그리고 useEffect의 반환값은 함수가 되어야 하는데, async를 바로 써버리면 promise 객체가 반환값이 되어 잘못된 코드가 되어버린다. 그래서 속에다가 async함수를 따로 작성하고 그 안에서 axios를 사용한다.

대표적인 커스텀 훅 : https://usehooks.com/useWindowSize/

profile
공부일기
post-custom-banner

0개의 댓글