본문 바로가기
React/Keeper-app | To-Do-app clone

[To-Do App] 최종 | input 부분 컴포넌트로 빼기

by CodeMia 2022. 4. 16.

이제는 input과 button을 묶어 <InputArea /> 컴포넌트로 따로 빼보자. 

 

 

 

 

현재 App.js 코드는 다음과 같다. 

Input과 관련된 내용을 InputArea로 옮긴다. 

 

import React, { useState } from "react";
import ToDoItem from "./ToDoItem";

function App() {
  const [inputText, setInputText] = useState("");
  const [items, setItems] = useState([]);

  function handleChange(event) {
    var newValue = event.target.value;
    setInputText(newValue);
  }

  function addItem() {
    setItems((prevItems) => {
      return [...prevItems, inputText];
    });
    setInputText("");
  }

  function deleteItem(id) {
    setItems((prevItems) => {
      return prevItems.filter((item, index)=>{
        return index !== id;
      })
    });
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <div className="form">
        <input onChange={handleChange} type="text" value={inputText} />
        <button onClick={addItem}>
          <span>Add</span>
        </button>
      </div>
      <div>
        <ul>
          {items.map((todoItem, index) => (
            <ToDoItem
              key={index}
              id={index}
              todoItem={todoItem}
              onChecked={deleteItem}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;

 

 

 

InputArea

 

App.js에 있는 함수를 연결 할 땐 props.함수이름으로 받으면 됨.

 

 

 

 

App.js에서 inputText와 setInputText가 없어져서 에러가 남

 

addItem() 함수를 InputArea에서 트리거 하고서 

addItem() 함수에 inputText를 받아와 사용할 수 있다. 

 

 

 

addItem 함수를  InputArea로 보내어 props로 렌더하기 

App.js

 

 

 

InputArea에서 props으로 받아 버튼이 클릭 됐을 때 함수를 실행 시킨다. 

 

 

 

 

App.js에 있는 addItem 함수에 

InputArea 있는 InputText를 받아야하는 데 어떻게 해야할까? 

 

InputArea에 있는 addItem에 파라미터로 현재의 inputText를 넣어주어 

클릭 했을 때 익명 함수로 받게 하고, addItem이 실행되도록 한다. 

 

 

 

 

 

 

 

 

현재의 inputText을 받아

 

 

 

 

App.js에 있는 addItem 함수의 파라미터로 넣는다.

 

 

 

Input 비워주는 setInputText도 여기 있을 필요가 없기 때문에 

InputArea로 옮겨준다. 

 

 

 

 

 

 


최종 코드 

 

 

 

App.js

import React, { useState } from "react";
import ToDoItem from "./ToDoItem";
import InputArea from "./InputArea";

function App() {
  const [items, setItems] = useState([]);

  function addItem(inputText) {
    setItems((prevItems) => {
      return [...prevItems, inputText];
    });
  }

  function deleteItem(id) {
    setItems((prevItems) => {
      return prevItems.filter((item, index) => {
        return index !== id;
      });
    });
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <InputArea addItem={addItem} />
      <div>
        <ul>
          {items.map((todoItem, index) => (
            <ToDoItem
              key={index}
              id={index}
              todoItem={todoItem}
              onChecked={deleteItem}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;

 

 

 

 

InputArea.js

import React, { useState } from "react";

function InputArea(props) {
const [inputText, setInputText] = useState("");

function handleChange(event) {
var newValue = event.target.value;
setInputText(newValue);
}

return (
<div className="form">
<input onChange={handleChange} type="text" value={inputText} />
<button
onClick={() => {
props.addItem(inputText);
setInputText("");
}}
>
<span>Add</span>
</button>
</div>
);
}

export default InputArea;

 

 

ToDoItem.js

import React from "react";

function ToDoItem(props) {
return (
<div
onClick={() => {
props.onChecked(props.id);
}}
>
<li>{props.todoItem}</li>
</div>
);
}

export default ToDoItem;

 

 

HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>React App</title>
<link
rel="stylesheet"
/>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<div id="root"></div>
<script src="../src/index.js" type="text/jsx"></script>
</body>
</html>

 

 

CSS

body {
background-color: #ffeaa7;
min-height: 70vh;
padding: 1rem;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
color: hsl(198, 1%, 29%);
font-family: "Architects Daughter", cursive;
text-align: center;
font-size: 130%;
}

.container {
width: 100%;
height: auto;
min-height: 500px;
max-width: 500px;
min-width: 250px;
background: #f1f5f8;
background-image: radial-gradient(#bfc0c1 7.2%, transparent 0);
background-size: 25px 25px;
border-radius: 20px;
box-shadow: 4px 3px 7px 2px #00000040;
padding: 1rem;
box-sizing: border-box;
}
.heading {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
}
.heading h1 {
transform: rotate(2deg);
padding: 0.2rem 1.2rem;
border-radius: 20% 5% 20% 5%/5% 20% 25% 20%;
background-color: #fdcb6e;
font-size: 1.5rem;
}

.form input {
box-sizing: border-box;
background-color: transparent;
padding: 0.7rem;
border-bottom-right-radius: 15px 3px;
border-bottom-left-radius: 3px 15px;
border: solid 3px transparent;
border-bottom: dashed 3px #fdcb6e;
font-family: "Architects Daughter", cursive;
font-size: 1rem;
color: hsla(260, 2%, 25%, 0.7);
width: 70%;
margin-bottom: 20px;
}

button {
padding: 0;
border: none;
font-family: "Architects Daughter", cursive;
text-decoration: none;
padding-bottom: 3px;
border-radius: 5px;
background-color: #ffeaa7;
}
button span {
background: #f1f5f8;
display: block;
padding: 0.5rem 1rem;
border-radius: 5px;
border: 2px solid hsl(198, 1%, 29%);
}

li {
text-align: left;
position: relative;
padding: 0.5rem;
}

 

댓글