#3 To-Do 앱 최적화 하기 - 3

김민성·2023년 5월 1일
0
post-thumbnail

할 일 목록 부분을 위한 컴포넌트 생성하기 (컴포넌트 분리하기)

지금까지 하나의 컴포넌트에 모두를 넣었지만,

컴포넌트를 분리한다면 구분하기도 쉽고, 재사용성을 높일 수 있다.

먼저, 할 일 목록 부분 (리스트)을 새로운 컴포넌트에 넣어주자.

리스트 컴포넌트 생성

component 폴더를 생성하고 안에 List.js 파일을 생성해준다.

그리고 함수형 컴포넌트를 작성해준다. (rfc + enter을 하면 바로 함수형 컴포넌트가 자동으로 작성된다.)
(여담으로 rce + enter를 하면 클래스 컴포넌트)

import React from 'react'

export default function List() {
    return (
        <div>List</div>
    )
}

그리고, App.js 코드의 상단에 List를 import해오기 위해,

import List from "./components/List";

를 작성해준다.

리스트에 관련된 부분 가져오기

UI 부분 가져오기

App.js에서 리스트에 관련된 부분은, 리스트를 나열해주는 부분인

{todoData.map((data) => (
        <div style={getStyle(data.completed)} key={data.id}>
          <input type="checkbox" 
          defaultChecked={false} 
          onChange={() => handleCompleteChange(data.id)} />
          {data.title}
          <button style={btnStyle} 
          onClick={() => handleClick(data.id)}>x</button>
        </div>
      ))}

이부분을 가져오고, 버튼과 관련된 부분인

const btnStyle = {
    color: "#fff",
    border: "none",
    padding: "5px 9px",
    borderRadius: "50%",
    cursor: "pointer",
    float: "right"
  }

이부분도 List.js로 가져온다.

필요한 State, 함수 가져오기

const [todoData, setTodoData] = useState([]);

이 부분을 List.js로 가져오는것 보단 todoData를 Props로 내려주는 것이 더 좋다.
그래서 할일 목록 아래에 다음과 같이 내려준다.

return(
      <div className="container">
        <div className="todoBlock">
          <div className="title">
            <h1>할 일 목록</h1>
          </div>

          <List todoData={todoData} setTodoData={setTodoData} /> //이렇게 말이다.

이렇게 내려주면 부모 컴포넌트에서 내려준 Props를 사용할 수 있다.

export default function List({todoData, setTodoData}) {

이렇게 List.js에서 말이다.

이제 필요한 함수인 getStyle, handleClick, handleCompleChange를 App.js에서 List.js로 가져온다.

위의 과정을 모두 수행하면 App.js와 List.js의 코드는 다음과 같다. 컴포넌트를 분리하기 전과 똑같이 작동한다.

<App.js>

import React, {useState} from "react"; //react는 라이브러리이므로 컴포넌트를 가져와서 
import "./App.css"
import List from "./components/List";

export default function App() {

  const [todoData, setTodoData] = useState([]);
  const [value, setValue] = useState("");

  const handleChange = (e) => {
    setValue(e.target.value)
  }

  const handleSubmit = (e) => {
    e.preventDefault(); //페이지가 리로드 되는 것을 막아줌.

    //새로운 할 일 데이터
    let newTodo = {
      id: Date.now(),
      title: value,
      completed: false
    }

    //원래 있던 할 일에 새로운 할 일 더해주기
    setTodoData(prev => [...prev, newTodo]);
    setValue("");

  }

    return(
      <div className="container">
        <div className="todoBlock">
          <div className="title">
            <h1>할 일 목록</h1>
          </div>

          <List todoData={todoData} setTodoData={setTodoData} />

      <form style={{ display: 'flex'}} onSubmit={handleSubmit}>
        <input 
        type='text' 
        name="value" 
        style={{ flex: '10', padding: '5px'}} 
        placeholder="해야 할 일을 입력하세요." 
        value={value}
        onChange={handleChange}
        />
      <input 
        type="submit"
        value="입력"
        className="btn"
        style={{flex: '1'}}
      />

      </form>

        </div>
      </div>
    )
  }

<List.js>

import React from 'react'

export default function List({todoData, setTodoData}) {

const btnStyle = {
    color: "#fff",
    border: "none",
    padding: "5px 9px",
    borderRadius: "50%",
    cursor: "pointer",
    float: "right"
}

const getStyle = (completed) => {
    return {
        padding: "10px",
        borderBottom: "1px #ccc dotted",
        textDecoration: completed ?"line-through" :"none"
    }
}

const handleClick = (id) => {
    let newTodoData = todoData.filter(data => data.id !== id);
    console.log('newTodoData', newTodoData);
    setTodoData(newTodoData)
}

const handleCompleteChange = (id) => {
    let newTodoData = todoData.map(data => {
        if(data.id === id) {
            data.completed = !data.completed; // 반대로
        }
        return data;
    })
    setTodoData(newTodoData);
}


    return (
        <div>
            {todoData.map((data) => (
            <div style={getStyle(data.completed)} key={data.id}>
            <input type="checkbox" 
            defaultChecked={false} 
            onChange={() => handleCompleteChange(data.id)} />
            {data.title}
            <button style={btnStyle} 
            onClick={() => handleClick(data.id)}>x</button>
            </div>
            ))}
        </div>
    )
}

구조 분해 할당(Destructuring)

구조 분해 할당이란 ? (ES6)

-> 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 Javascript 표현식.

Clean Code를 위해 객체 구조 분해 할당을 사용한다.


이를 객체 구조 분해 할당을 사용해 다음과 같이 깔끔하게 가져와줄 수 있다.

깊게 들어간 객체 구조 분해 할당


아래의 그림을 보면 person 안에 address가 있고, address 안에 zipcode, street, number이 들어간 것을 볼 수 있다.

배열 구조 분해 할당


위와 같이 코드를 길게 작성하기 보다는 배열 구조 분해 할당을 활용해 아래왁 같이 작성해주면 Clear한 코드를 작성할 수 있다.

아래의 코드도 살펴보자.

아래의 for문 안을 보면, name을 n으로 가져올 수 있고, family 안의 father을 f로 가져올 수 있게끔 배열 구조 분해 할당을 해놓았다.
그렇게 console.log를 통해 출력되는 값을 보면 잘 가져오는 것을 확인 할 수 있다.

Form 부분을 위한 컴포넌트 생성하기

App.js에서 List.js로 필요한 부분을 가져와 컴포넌트를 분리한 것 처럼, 마찬가지로 Form.js에 필요한 부분을 가져와 분리해준다.

Form 컴포넌트 생성


Form.js를 위와 같이 생성해준다.

그리고 App.js에서 Form.js를 import 해오기 위해 App.js 코드의 상단에 다음과 같이 작성한다.

import Form from "./components/Form";

UI 부분 가져오기

App.js에서 아래의 코드 부분을 Form.js로 가져온다.

<form style={{ display: 'flex'}} onSubmit={handleSubmit}>
        <input 
        type='text' 
        name="value" 
        style={{ flex: '10', padding: '5px'}} 
        placeholder="해야 할 일을 입력하세요." 
        value={value}
        onChange={handleChange}
        />
      <input 
        type="submit"
        value="입력"
        className="btn"
        style={{flex: '1'}}
      />

      </form>

필요한 함수 가져오기

App.js에서 handleChange 함수를 Form.js로 가져온다.

const handleChange = (e) => {
    setValue(e.target.value)
  }

Form 컴포넌트에 Props 내려주기

handleSubmit 함수와 value state, setValue state를 Props로 내려준다.

return(
      <div className="container">
        <div className="todoBlock">
          <div className="title">
            <h1>할 일 목록</h1>
          </div>

          <List todoData={todoData} setTodoData={setTodoData} />

          <Form value={value} setValue={setValue} /> // 이렇게 말이다.

그리고 이 Props로 필요한 데이터 함수, 즉 value와 setValue를 가져와준다.

export default function Form({value, setValue}) {

handleSubmit 함수도 가져와야하는데, 이 함수 자체를 Form.js에 가져오기 보다는,

 const handleSubmit = (e) => {
    e.preventDefault(); //페이지가 리로드 되는 것을 막아줌.

    //새로운 할 일 데이터
    let newTodo = {
      id: Date.now(),
      title: value,
      completed: false
    }

    //원래 있던 할 일에 새로운 할 일 더해주기
    setTodoData(prev => [...prev, newTodo]);
    setValue("");

  }

코드를 보면 newTodo state도 'setTodoData(prev => [...prev, newTodo]);'이 안에 있기 때문에 App.js 컴포넌트 안에서 처리해주는 것이 더 좋다.
따라서 Props로 내려주는 것이 더 좋다.

<Form handleSubmit={handleSubmit} value={value} setValue={setValue} />

그리고 이 Props로 필요한 데이터 함수, 즉 handleSubmit을 가져와준다.

export default function Form({handleSubmit, value, setValue}) {
profile
다양한 활동을 통해 인사이트를 얻는 것을 즐깁니다. 저 또한 인사이트를 주는 사람이 되고자 합니다.

0개의 댓글

관련 채용 정보