[React Hooks] Component 간의 state 전달

박은지·2022년 2월 20일
0

Todo Application

목록 보기
3/7
post-thumbnail

1. 남은 할 일의 개수 표현

<h1>Todo Application</h1> 아래에 할 일의 개수를 표현해보자.

App.js

App.js에 Header 컴포넌트를 추가해주고, props로 todos를 전달해준다.

// App.js
. . .
import Header from './components/Header.jsx';
. . .
return(
    <>
      <h1>Todo Application</h1>

      <Header todos={todos} />

      <form action="">
        <input type="text" name="" onChange={changeInputData}/>
        <button onClick={addTodo}>ADD</button>
      </form>

      <List todos={todos} loading={loading}/>
    </>
  );
}

export default App;

Header.jsx
components 폴더 안에 Header.jsx 파일을 생성해준다.

// Header.jsx

import React from 'react';
import './Header.css';

function Header({todos}) {

  // 미완료 상태(done: false)인 todo들의 배열
  const undoneTasks = todos.filter(todo => todo.done === false);

  return(
    <div className='countInfo'>{`남은 할 일 : ${undoneTasks.length}`}</div>
  );
}

export default Header;

현재 initialTodoData.js의 Todo들 중 완료상태done: true는 3개, 미완료 상태done: false는 4개이다.
따라서 우리가 확인할 수 있는 결과는 "남은 할 일: 4"이다.

2. Done 상태 표현

TodoList 목록 중 특정 할 일을 클릭했을 때 완료/미완료 상태 표현을 할 수 있도록 처리해보자.

List.jsx
소스코드의 <li key={todo.todoCode}>{todo.title}</li> 부분을 Item 컴포넌트에 key값과 todos를 전달하는 형식으로 수정한다.

// List.jsx

import React from 'react';
import Item from './Item.jsx';

function List({todos, loading}) {

  let todoList = <div>Loading...</div>;
  if(!loading) todoList = todos.map(todo => <Item key={todo.todoCode} todo={todo} />);
  
  return(
    <ul>
      {todoList}
    </ul>
  );
}

export default List;

Item.jsx
Item.jsx 폴더를 생성하고,

// Item.jsx

import React from 'react';

function Item({todo}) {

  // toggleDone : 할 일의 완료/미완료 상태를 표현하는 함수
  const toggleDone = () => {

  }

  return(
    <li data-id={todo.todoCode} onClick={toggleDone}>{todo.title}</li>
  );
}

export default Item;

App.js
할 일의 Done 상태 값을 바꾸는 함수 changeTodoDone 를 작성한다.
여기서 Done이 true이면 완료상태, false이면 미완료 상태를 의미한다.
그리고 List 컴포넌트와 LIst 컴포넌트 안의 Item 컴포넌트에 changeTodoDone={changeTodoDone} props를 전달해주는 처리를 한다.

// App.js

import React, { useEffect, useState } from 'react';
import './App.css';

// Custom Hook
import useFetch from './useFetch.js';

// Components 
import List from './components/List.jsx';
import Header from './components/Header.jsx';



// App Component
function App() {

  const [todos, setTodos] = useState([]);  // todos
  const [newTodo, setNewTodo] = useState();  // new todos
  
  const loading = useFetch(setTodos, 'http://localhost:4000/initialtodos');

  const changeInputData = (e) => { // changeInputData : newTodo에 input에 입력한 내용을 저장하는 함수
    setNewTodo(e.target.value);
  }
  
  const addTodo = (e) => { // addTodo : 새로운 todo를 배열에 추가하는 함수
    e.preventDefault(); // 기본값 form 전송방지
    setTodos([...todos, {'title': newTodo, 'todoCode': todos.length, 'contents': '', done: false, edit: false}]);
  }

  // changeTodoDone
  const changeTodoDone = (todoCode) => {
    const updateTodos = todos.map(todo => {
      if(todo.todoCode === todoCode) {
        if(todo.done === true) todo.done = false;
        else todo.done = true;
      }
      return todo;
    })
    setTodos(updateTodos);
    // console.log(updateTodos);
  }

  useEffect(() => {
    console.log("새로운 내용이 추가되었습니다.", todos);
  }, [todos]);


  return(
    <>
      <h1>Todo Application</h1>

      <Header todos={todos} />

      <form action="">
        <input type="text" name="" onChange={changeInputData}/>
        <button onClick={addTodo}>ADD</button>
      </form>

      <List todos={todos} loading={loading} changeTodoDone={changeTodoDone} />
    </>
  );
}

export default App;

List.jsx

// List.jsx

import React from 'react';
import Item from './Item.jsx';

function List({todos, loading, changeTodoDone}) {

  let todoList = <div>Loading...</div>;
  
  if(!loading) todoList = todos.map(todo => 
    <Item key={todo.todoCode} todo={todo} changeTodoDone={changeTodoDone} />
  );

  return(
    <ul>
      {todoList}
    </ul>
  );
}

export default List;

Item.jsx
Item 컴포넌트에서 Done 상태값이 변경되었다는 것을 시각적으로 보이도록 하자.

// Item.jsx

import React from 'react';
import './Item.css';

function Item({todo, changeTodoDone}) {

  // toggleDone : 할 일의 완료/미완료 상태를 표현하는 함수
  const toggleDone = (e) => {
    changeTodoDone(e.target.dataset.id)
  }

  // todo의 done 속성값이 true(완료)이면 'done', false(미완료)이면 ''
  const ItemClassName = todo.done === true ? 'done' : '';

  return(
    <li data-id={todo.todoCode} onClick={toggleDone} className={ItemClassName}>{todo.title}</li>
  );
}

export default Item;

Item.css

/* Item.css */

.done {
  text-decoration: line-through;
  font-style: italic;
}


💡 지금까지 각 컴포넌트에 props를 넘기고 넘겨주는 방식으로 todos를 전달해 주었다.
직접 해본 사람은 알겠지만 이 방법은 너무나 번거롭다ㅠ
이 문제를 해결할 수 있는 방법이 Context APIuseContext를 사용하는 것이다.
궁금한 사람은 다음 글로 커몬~!

0개의 댓글