React Practice(CRUD)

YOBY·2023년 10월 22일
0
import { useState } from "react";
import "./App.css";

헤더 :

function Header(props) {
  return (
    <header>
      <h1>
        <a
          href="/"
          onClick={(event) => {
            /* a태그의 기능을 preventDefault로 막고
            props객체로 받아온 onChangeMode속성의 기능을 실행을 시킨다. */
            event.preventDefault();
            props.clickHeader();
          }}
        >
          {props.title}
        </a>
      </h1>
    </header>
  );
}

메뉴 :

function Nav(props) {
  let topics = [];

  for (let topic of props.topics) {
    topics.push(
      <li key={topic.id}>
        {/* 유니크한 키(식별자)를 주어야한다. (반복문 안에서 고유해야하는 키값이다.) */}
        {/* 리액트에서는 반복 등 자동으로 생성되는 태그들을 추적하기 위해서는 각각의 태그에 유니크한 키를 주겠금 한다. */}
        <a
          id={topic.id}
          href={"/read/" + topic.id}
          onClick={(event) => {
            event.preventDefault();
            /* target은 이벤트가 발생된 주체 즉, a태그를 가르키며 a태그의 id를 가져온다. */
            props.clickID(event.target.id);
            /* props.clickID(topic.id) <= 이런식으로 해도 되지만 반복되는 태그에 식별자를 두어 해당 식별자의 id값을 가져오는게 맞는 방식이다.*/
          }}
        >
          {topic.title}
        </a>
      </li>
    );
  }

  return (
    <nav>
      <ol>{topics}</ol>
    </nav>
  );
}

내용 :

function Article(props) {
  return (
    <article>
      <h2>{props.title}</h2>
      <h4>{props.content}</h4>
    </article>
  );
}

CRUD :

function Create(props) {
  return (
    <article>
      <h2>생성합니다.</h2>
      {/* form태그 submit시켰을때 onSubmit 이벤트를 실행시킬수 있다. */}
      <form
        onSubmit={(e) => {
          e.preventDefault();
          let text = [e.target.title.value, e.target.content.value];
          props.onCreate(text);
        }}
      >
        <p>
          <input type="text" name="title" placeholder="제목"></input>
        </p>
        <p>
          <textarea name="content" placeholder="내용"></textarea>
        </p>
        <p>
          <input type="submit" value="생성"></input>
        </p>
      </form>
    </article>
  );
}
function Update(props) {
  /* input태그에 value는 고정되어 있어서 props.title로만 지정하면 변경되지 않아서 state 초기값으로 잡아주고
  변경될때마다 랜더링을 해줘서 변경된 값을 value에 담아준다. => 즉 props로 넘어온 값을 state로 환승한것이다. */
  const [title, setTitle] = useState(props.title);
  const [body, setBody] = useState(props.title);

  return (
    <article>
      <h2>수정 합니다.</h2>
      {/* form태그 submit시켰을때 onSubmit 이벤트를 실행시킬수 있다. */}
      <form
        onSubmit={(e) => {
          e.preventDefault();
          let title = e.target.title.value;
          let body = e.target.content.value;
          props.onUpdate(title, body);
        }}
      >
        <p>
          {/* input태그에 value에 해당 props로 받아온 값을 넣어줬더니 키보드를 입력해도 추가 및 수정이 되지 않았다.
          그래서 state 2개를 더 생성해서 내부에 먼가 동작할때마다 set으로 수정해서 다시 해당 value에 넣어줬다. */}
          <input
            type="text"
            name="title"
            placeholder="제목"
            /* html에서는 onChange이벤트는 값이 바뀌고 마우스가 바깥쪽으로 빠져나갈때 이벤트가 발생되는데
            리액트에서는 값이 입력될때마다 onChage 이벤트가 발생된다. */
            value={title}
            onChange={(event) => {
              /* 콘솔을 찍어보면 입력될때마다 onChange이벤트가 발생되어서 랜더링이 되는모습을 볼수가있다.
              그래서 값을 입력할때마다 state를 사용하여 변경된 값을 담고 value에 변경된 값을 다시 보여줌으로써 입력시킬수가 있다. */
              console.log(event.target.value);
              setTitle(event.target.value);
            }}
          ></input>
        </p>
        <p>
          <textarea
            name="content"
            placeholder="내용"
            value={body}
            onChange={(e) => {
              setBody(e.target.value);
            }}
          ></textarea>
        </p>
        <p>
          <input type="submit" value="수정"></input>
        </p>
      </form>
    </article>
  );
}

메인 컴포넌트 :

function App() {
  const [mode, setMode] = useState("Welcome");
  const [id, setId] = useState(null);

  const [topics, setTopics] = useState([
    { id: 1, title: "html", body: "html is ..." },
    { id: 2, title: "css", body: "css is ..." },
    { id: 3, title: "jss", body: "jss is ..." },
  ]);

  let content = null;
  let contextControl = null;

  if (mode === "Welcome") {
    content = <Article title="Welcome" content="Hello, Web" />;
  } else if (mode === "Read") {
    contextControl = (
      /* 이렇게 해당 li태그가 ul안에 있는데 2개의 li를 만들기 위해서는 이런식으로 <>빈 태그를 생성하면
      html상에서는 보이지 않고 2개의 li태그를 하나의 변수에 담을수 있다. */
      <>
        <li>
          <a
            href={"/update/" + id}
            onClick={(e) => {
              e.preventDefault();
              setMode("Update");
            }}
          >
            Update
          </a>
        </li>
        <li>
          <input
            type="button"
            value="삭제"
            onClick={() => {
              const newTopics = [];
              for (let topic of topics) {
                if (topic.id !== Number(id)) {
                  newTopics.push(topic);
                }
              }
              setTopics(newTopics);
              setMode("Welcome");
            }}
          ></input>
        </li>
      </>
    );

    for (let i = 0; i < topics.length; i++) {
      /* useState값으로 set해주면 문자열로 저장된다. 그래서 number()함수를 통해서 정수로 변환시켰다. */
      if (topics[i].id === Number(id)) {
        content = <Article title={topics[i].title} content={topics[i].body} />;
      }
    }
  } else if (mode === "Create") {
    content = (
      <Create
        onCreate={(result) => {
          const newTopic = {
            id: topics.length + 1,
            title: result[0],
            body: result[1],
          };

          const newTopics = [...topics];
          newTopics.push(newTopic);
          setTopics(newTopics);
        }}
      />
    );
  } else if (mode === "Update") {
    let title = null;
    let body = null;

    for (let i = 0; i < topics.length; i++) {
      if (topics[i].id === Number(id)) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }

    content = (
      <Update
        title={title}
        body={body}
        onUpdate={(title, body) => {
          /* 수정이 완료된 값으로 updatedTopic에 담아준다.*/
          const updatedTopic = { id: Number(id), title: title, body: body };
          const newTopics = [...topics];

          let i = 0;
          for (let topic of newTopics) {
            if (topic.id === Number(id)) {
              newTopics[i] = updatedTopic;
              break;
            }
            i++;
          }
          setTopics(newTopics);
          setMode("Read");
        }}
      />
    );
  } else if ("Delete") {
  }

  return (
    <div>
      <Header
        title="REACT"
        clickHeader={() => {
          setMode("Welcome");
        }}
      />

      <Nav
        topics={topics}
        clickID={(id) => {
          setMode("Read");
          /* 내부 컴포넌트에서 클릭하면 해당 id를 파라미터로 받아서 state 내부 상태값 변경하여 랜더링 */
          setId(id);
        }}
      />

      {content}

      <ul>
        <li>
          <a
            href="/create"
            onClick={(e) => {
              e.preventDefault();
              setMode("Create");
            }}
          >
            Create
          </a>
        </li>

        {contextControl}
      </ul>
    </div>
  );
}
export default App;

0개의 댓글