본문 바로가기

[내일배움캠프]/TIL

22.12.13)투두앱을 최종정리한 32일차

rfce

함수형 컴포넌트를 rfce 네 글자로 react임포트와 파일이름으로 컴포넌트를 생성해줍니다. 

vs code 확장 프로그램 ->es7 검색 후 ES7+ React/Redux/React-Native snippets 설치

jsx파일에 rfce를 입력 후 엔터를 치면 완성.

 

 

 

 

 

 

 

유니크한 키가 있어야 한다는 오류.

맵으로 돌릴 때는 코드 전체를 리턴하기 때문에 몇번째 div인지 확인이 불가능하다. 그래서 div안에 key라는 속성을 넣어야 한다.

key={todo.id}

 

 

 

투두앱 만들기[최종정리]

app.jsx

import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import "./App.css";
import Header from "./components/Header";
import Input from "./components/Input";
import TodoList from "./components/TodoList";

function App() {
  //state : todo라는 객체를 여러개 가지고 있는 배열이다.
  const [state, setState] = useState(stateList);

  return (
    <>
      <Header>헤더</Header>
      <main style={{ padding: "20px", background: "green" }}>
        {/* 인풋을 만들어 입력하는 부분 */}
        {/* 인풋태그2개와 버튼이 들어간다 */}
        <Input setState={setState} />
        {/* input태그를 에 setState를 넣어 input.jsx에서도 사용 가능하게 props로 내려준다*/}
        {/* todolist를 출력하는 부분 */}
        {/* 투두와 완료가 같으니 안에서 값만 제어하면 된다.props isActive와 state값을 넘겨준다. */}
        <TodoList isActive={true} state={state} setState={setState} />
        <TodoList isActive={false} state={state} setState={setState} />
      </main>
      <footer></footer>
    </>
  );
}

export default App;

const stateList = [
  {
    title: "제목",
    content: "내용",
    isDone: false,
    id: uuidv4(),
  },
  {
    title: "제목",
    content: "내용",
    isDone: true,
    id: uuidv4(),
  },
];

Header.jsx

import React from "react";

function Header({ children }) {
  //얘를 app.jsx의 children으로 넘겨주기 때문에 ()안에 children값을 준다.(props)
  return <header>{children}</header>;
}

export default Header;

 

Input.jsx

import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";

function Input({ setState }) {
  // 제목과 내용에 대한 state를 가지고 있어야 한다.
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  const handleSubmit = (event) => {
    //페이지 갱신을 막기위해 onSubmit이 가지고 있는event를 받아 preventDefault해주면 갱신이 방지된다.
    event.preventDefault();

    //타이틀과 콘텐츠가 입력되지 않은 것이 있다면 alert를 출력해
    //다만 handleSubmit함수의 기본 return동작때문에 오류가 발생해도 그냥 추가해버린다..
    //그래서 title과content에 return을 넣는다.
    if (!title) {
      return alert("제목을 입력해주세요");
    }
    if (!content) {
      return alert("내용을 입력해주세요");
    }

    const NewstateList = {
      title: title,
      content: content,
      isDone: false,
      id: uuidv4(),
    };

    //셋팅된 title과content를 state에 넣는 작업.이전값을 인자로 받는다!!!!
    setState((prev) => {
      //이전값은 가지고 있고 새로운값을 더해라.
      return [...prev, NewstateList];
    });
    //useState를 통해서 값을 변경해줬을 때 변경방법은 set~~밖에 없으니 이것을 통해
    //추가버튼시 input태그의 공백으로 바꿔준다.
    //prev의 방법은 배열은 굉장히 용이하나 문자열은....그냥 그렇다...
    setTitle("");
    setContent("");
  };
  const handleTitleChange = (event) => {
    setTitle(event.target.value);
  };
  const handleContentChange = (event) => {
    setContent(event.target.value);
  };

  return (
    <section>
      <form onSubmit={handleSubmit}>
        {/* 컴포넌트를 나눠서 상위  ->하위 컴포넌트로 props를 보내고 관리할 수 있도록 
    (prop를 보내는 대상이 state니까 그 하위 컴포넌트를 통해 set 등의 기능을 가진 컴포넌트를 만들것이다.)
    추가 버튼을 누르면 리스트로 들어가게 한다. */}
        제목 : <input value={title} onChange={handleTitleChange} />
        내용 : <input value={content} onChange={handleContentChange} />
        {/* input의 내용과 title,content는 같이 가야한다. 내용이 입력될 때마다 state가 갱신되야하니까 */}
        <button>추가</button>
      </form>
    </section>
  );
}

export default Input;

TodoList.jsx

import React from "react";
import Todo from "./Todo";

function TodoList({ state, setState, isActive }) {
  //props로 state를 받아온다. 이후 맵함수를 통해 전체를 돌린다.
  return (
    //js문법이니 중괄호. app.jsx에서 todoList를 2개 출력인데 완료와 되지않은 것으로 나눠야하는데
    //여기서 props 하나만 전달하면 될 것같다.
    <div>
      {/* 해야할 것과 완료된 것을 나눠야 하기 때문에 isActive를 통해 제어한다 
      isActive를 통해 투두에 있는 배열도 제어가 가능하다.*/}
      <h4>{isActive === true ? "해야할 것" : "완료된 것"}</h4>
      {state
        //filter를 통해 해야할 것과 완료된 것을 구분해서 나눈다.여기의 todo는 state하나하나를 말한다.
        .filter((todo) => todo.isDone === !isActive) //todo의 isDone이 isActive가 아니것만 나오게 한다.
        .map((todo) => {
          // 투두가 가지고 있는 타이틀.
          return <Todo todo={todo} isActive={isActive} setState={setState} />;
        })}
    </div> //빈태그가 아닌 div로 설정해야 안의 내용을 css 제어 가능하다.>
  );
}

export default TodoList;

Todo.jsx

import React from "react";

function Todo({ todo, isActive, setState }) {
  const handleDeleteBttn = () => {
    //삭제했던 게 없어지고 기존의 state가 갱신되야한다.그래서 setState를 써야한다.
    //삭제하려는 id를 접근하여 삭제한다.
    setState((prev) => prev.filter((List) => List.id !== todo.id));
    //List가 가지고 있는 id가 todo가 가지고 있는 id랑 다르면 filter해라.일치하는id빼고 갱신.
  };
  const handleSwitchBttn = () => {
    //삭제와 마찬가지로 setState를 통해 기존값으로 변경하고,isdone이 true,false왓다갓다하게
    //이전값을 map을 통해서 prev에 있는 todo를 하나하나씩들어간다.컴포넌트 자체의 id와 비교해서 같으면
    //내가 완료 버튼을 눌렀을 때 가리킨 컴포넌트와 일치하면 객체를 바꿔준다.
    setState((prev) =>
      prev.map((switchtodo) => {
        //switchtodo가 가지고 있는게 저 투두리스트 통틀어 하난데 만약 첫번째 완료버튼을 누르면
        //switchtodo.id가 첫번째 id를 가리키고 있는건데 구조분해 할당을 통해 안에 바뀔값만 다시 설정해주면 된다.
        //isDone만 원래 가지고 있는 값이랑 반대로 넣어준다.그럼 새로운 값으로 리턴이 된다.아니면 원래 값으로 리턴한다.
        //!가 부정의 뜻이니까 원래 것과 반대로 한다..라는 뜻같다.

        if (switchtodo.id === todo.id) {
          return { ...switchtodo, isDone: !switchtodo.isDone };
        } else {
          return switchtodo;
        }
      })
    );
  };

  return (
    //여기의 todo는 state의 투두 1개만 해당된다.
    <div style={{ border: "2px solid blue" }} key={todo.id}>
      <h4>{todo.title}</h4>
      <p>{todo.content}</p>
      <button onClick={handleSwitchBttn}>{isActive ? "완료" : "취소"}</button>
      <button onClick={handleDeleteBttn}>삭제</button>
    </div>
  );
}

export default Todo;

 

후발대 5일차 정리..

후발대)React 투두앱을 배운 5일차 (tistory.com)

 

후발대)React 투두앱을 배운 5일차

변수가 바뀔 수 있도록 input이 change되게 한다. ?event인자가 없는데 어떻게 있나? 브라우저의 모든 이벤트는 액션이 있을 때 무조건 인자로 전달한다. console.log로 찍었을 때 targer안에 value가 있다.

jhee-web.tistory.com