본문 바로가기
강의 정리/기타 강의 정리

[리액트] 노마드코더 투두리스트(Todo list) 복습

by ㅇㅇ우너자나나 2022. 3. 31.

초보자의 입장에서 적은 내용으로, 틀리거나 정확하지 않을 수 있습니다.

 

[리액트] 노마드코더 투두리스트(Todo list) 복습

공부 기간: 22/03/31


 

결과

 

import { useState } from "react";

export default function App() {
  const [todo, setTodo] = useState("");
  const [todos, setTodos] = useState([]); // [] 리스트임을 표기하는 것 뿐임. 어차피 () 안에 통째로 todos가 되는거라 list를 받으면 알아서 todos에 리스트 전달됨.

  const onChange = (event) => {
    setTodo(event.target.value);
  };

  const onSubmit = (event) => {
    event.preventDefault();
    if (todo === "") {
      return;
    } else {
      setTodos((current) => [...current, todo]);
      setTodo("");
    }
  };

  return (
    <>
      <h1>Todos : {todos.length}개</h1>
      <form onSubmit={onSubmit}>
        <input placeholder="할일입력" value={todo} onChange={onChange} />
        <button>Add</button>
      </form>
      {todos.map((element, index)=><li key={index}>{element}</li>)}
    </>
  );
}

 

 

 

해결방안 

1. form태그로 감싼 input태그 만들기, submit 시 내용 출력되도록 만들기

export default function App() {
  const [value, setValue] = useState("");
  
  const onChange = (event) => {
    setValue(event.target.value);
  };
  const onSubmit = (event) => {
    event.preventDefault();
    console.log(value)
  }

  return (
    <>
      <form onSubmit = {onSubmit}>
        <input placeholder="할일입력" value={value} onChange={onChange}></input>
        <button>Add</button>
      </form>
    </>
  );
}

 

2. spread연산자를 이용해 할일(todos) 저장해두는 배열 state만들기

export default function App() {
  const [todo, setTodo] = useState("");
  const [todos, setTodos] = useState([]); // [] 리스트임을 표기하는 것 뿐임. 어차피 () 안에 통째로 todos가 되는거라 list를 받으면 알아서 todos에 리스트 전달됨.

  const onChange = (event) => {
    setTodo(event.target.value);
  };

  const onSubmit = (event) => {
    event.preventDefault();
    if (todo === "") {
      return;
    } else {
      setTodos((current) => [todo, ...current]);
      setTodo("");
    }

  };

  return (
    <>
      <h1>{todos.length}</h1>
      <form onSubmit={onSubmit}>
        <input placeholder="할일입력" value={todo} onChange={onChange}></input>
        <button>Add</button>
      </form>
    </>
  );
}

 

3. 할일 저장돼있는 todos 배열 state를 이용해 li태그로 렌더링해주기

import { useState } from "react";

export default function App() {
  const [todo, setTodo] = useState("");
  const [todos, setTodos] = useState([]); // [] 리스트임을 표기하는 것 뿐임. 어차피 () 안에 통째로 todos가 되는거라 list를 받으면 알아서 todos에 리스트 전달됨.

  const onChange = (event) => {
    setTodo(event.target.value);
  };

  const onSubmit = (event) => {
    event.preventDefault();
    if (todo === "") {
      return;
    } else {
      setTodos((current) => [...current, todo]);
      setTodo("");
    }
  };

  return (
    <>
      <h1>Todos : {todos.length}개</h1>
      <form onSubmit={onSubmit}>
        <input placeholder="할일입력" value={todo} onChange={onChange} />
        <button>Add</button>
      </form>
      {todos.map((element, index)=><li key={index}>{element}</li>)}
    </>
  );
}

 

 

비고

강의 내용에 삭제버튼 추가했다.

1. todos를 map으로 찍어줄 때 button태그도 함께 생성했다. 그리고 버튼에 클릭이벤트를 부여하여 클릭시 부모 엘리먼트를 삭제해주면 된다.

 

 

import { useState } from "react";

export default function App() {
  const [todo, setTodo] = useState("");
  const [todos, setTodos] = useState([]);
  const onChange = (event) => {
    setTodo(event.target.value);
  };

  const onSubmit = (event) => {
    event.preventDefault();
    if (todo === "") {
      return;
    } else {
      setTodos((current) => [...current, todo]);
      setTodo("");
    }
  };
  const onDelete = (event) => {
    event.target.parentElement.remove();
  }
  return (
    <>
      <h1>Todos : {todos.length}개</h1>
      <form onSubmit={onSubmit}>
        <input placeholder="할일입력" value={todo} onChange={onChange} />
        <button>Add</button>
      </form>
      {todos.map((element, index) => {
        return (
            <li key={index}>{element}<button onClick={onDelete}>delete</button></li>
        );
      })}
    </>
  );
}

하지만 이렇게하면 배열 내부 엘리먼트 자체가 삭제되는 것이 아니기 때문에 todos.length는 그대로 남아있다.

 

 

 

2. 단순히 부모엘리먼트 삭제가 아닌 배열 내부의 데이터를 삭제하고 싶을 땐 filter를 사용하여 todos 배열을 바꿔준다.

const onDelete = (index) => {
    setTodos(todos.filter((item, todoindex) => index !== todoindex));
  }

  return (
    <>
      <h1>Todos : {todos.length}개</h1>
      <form onSubmit={onSubmit}>
        <input placeholder="할일입력" value={todo} onChange={onChange} />
        <button>Add</button>
      </form>
      {todos.map((element, index) => {
        return (
            <li key={index}>{element}<button onClick={() => onDelete(index)}>delete</button></li>
        );
      })}
    </>
  );

이렇게 해주면 된다.

(onDelete 이벤트가 활성화되면 그 엘리먼트의 index가 onDelete함수에 전달된다. 그리고 filter함수와 setTodos를 통해 todos를 새로 만들어주는데, filter함수가 배열의 모든 엘리먼트를 하나씩 가져와서 엘리먼트의 인덱스가 전달받은 인덱스와 동일하면 그 엘리먼트는 제외하고 todos를 설정해주는 것이다.)

 

 

참고로 버튼태그 이벤트에서 onClick={() => onDelete(index)} 가 아닌 onClick={onDelete(index}로 하면 안된다. 

후자처럼 만들면 이벤트 만들어짐과 동시에 onDelete함수가 실행되기 때문에 여태 괄호를 빼고 onClick={onDelete} 처럼 만들었으나, 위 이벤트에는 반드시 index라는 파라미터를 받아와야 하므로 사용하고싶으면 전자처럼 사용해야한다.

 

*memo

- filter 함수도 map 과 마찬가지로 두번째 파라미터에 index를 받을 수 있다.