let's get IT with DAVINA ๐Ÿ’ป

React๋กœ TodoApp ๋งŒ๋“ค๊ธฐ (2)Create ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ ๋ณธ๋ฌธ

DEV_IN/React

React๋กœ TodoApp ๋งŒ๋“ค๊ธฐ (2)Create ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

๋‹ค๋นˆ์น˜์ฝ”๋“œ๐Ÿ’Ž 2023. 3. 2. 22:58
CSS ์ž‘์—… ํ›„, CRUD์˜ ์ฒซ๋ฒˆ ์งธ ๊ธฐ๋Šฅ์ธ Create ๊ธฐ๋Šฅ ๊ตฌํ˜„์— ๋“ค์–ด๊ฐ”๋‹ค.
⊕ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ!

์ด๋ ‡๊ฒŒ ํŒ์—…์ฐฝ/๋ชจ๋‹ฌ์ฐฝ ํ˜•ํƒœ๋กœ ๋„์šธ๊ผฌ์•ผ


  • TodoInsert.js
    • ๋ฐฐ๊ฒฝ์„ ๋‹ด๋‹นํ•ด์ฃผ๋Š” background div์™€
    • form์„ ํ•˜๋‚˜ ๋„ฃ์–ด์ฃผ๊ธฐ (์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜๋Š” input + ์ œ์ถœํ•˜๋Š” button ์š”์†Œ)

์ด๊ฑธ ์‚ฌ์šฉ์ž๊ฐ€ ⊕๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ๋•Œ๋งŒ ๋ชจ๋‹ฌ์„ ๋„์šฐ๊ณ  ์‹ถ์ž–์•„์š”?

  • App.js
import React, { useState } from "react";
import { MdAddCircle } from "react-icons/md";
import "./App.css";
import Template from "./components/Template";
import TodoInsert from "./components/TodoInsert";
import TodoList from "./components/TodoList";

//์™ธ๋ถ€์—์„œ ์„ ์–ธํ•ด์ฃผ๊ธฐ!
//๋ฐ‘์— ํ•จ์ˆ˜ ์•ˆ์— ์žˆ์œผ๋ฉด ํ•จ์ˆ˜๊ฐ€ ๋ฆฌ๋žœ๋”๋ง ๋ ๋•Œ๋งˆ๋‹ค ๊ณ„์† ์ฒ˜์Œ๊ฐ’์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ ๋•Œ๋ฌธ์—..
let nextId = 4;

const App = () => {
    const [insertToggle, setInsertToggle] = useState(false); //์ถ”๊ฐ€!

    const [todos, setTodos] = useState([
        {
            id: 1,
            text: "ํ• ์ผ 1",
            checked: true,
        },
        {
            id: 2,
            text: "ํ• ์ผ 2",
            checked: false,
        },
        {
            id: 3,
            text: "ํ• ์ผ 3",
            checked: true,
        },
    ]);

	//์ถ”๊ฐ€! toggle์ฐฝ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋Š” ํ•จ์ˆ˜!
    const onInsertToggle = () => {
        setInsertToggle((prev) => !prev);
    };
    
    //์ถ”๊ฐ€! ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’์ด ์—†์œผ๋ฉด alert, ์•„๋‹ˆ๋ฉด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด return!
        const onInsertTodo = (text) => {
        if (text === "") {
            return alert("ํ•  ์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.");
        } else {
            const todo = {
                id: nextId,
                text,
                checked: false,
            };
            setTodos((todos) => todos.concat(todo)); //์ƒํƒœ ๋ถˆ๋ณ€์„ฑ ์œ ์ง€ push ๋Œ€์‹  concat
            nextId++;
        }
    };

    return (
        <Template todoLength={todos.length}>
            <TodoList
                todos={todos}
                onInsertToggle={onInsertToggle}
            />
            <div className='add-todo-button' onClick={onInsertToggle}> //์ถ”๊ฐ€!
                <MdAddCircle />
            </div>
            //insertToggle์ด true์ผ๋•Œ๋งŒ insert๋ชจ๋‹ฌ์ฐฝ ๋„์›Œ์ฃผ๊ธฐ!
            {insertToggle && (
                <TodoInsert
                    onInsertToggle={onInsertToggle}
                    onInsertTodo={onInsertTodo}
                />
            )}
        </Template>
    );
};

export default App;
  • TodoInsert.js
import React, { useEffect, useState } from "react";
import { MdAddCircle } from "react-icons/md";
import { TiTrash, TiPencil } from "react-icons/ti";
import "./TodoInsert.css";

const TodoInsert = ({
    onInsertToggle,
    onInsertTodo
}) => {
    const [value, setValue] = useState("");

	//form์˜ ๊ฐ’์ด ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜์—ฌ ๋ฐ”๋€Œ๋ฉด ํ•ด๋‹น ๊ฐ’์œผ๋กœ value๊ฐ’ ๋ณ€๊ฒฝํ•ด์ฃผ๊ธฐ!
    const onChange = (e) => {
        setValue(e.target.value);
    };

	//form์˜ ๊ธฐ๋ณธ ์†์„ฑ, button type=submit์œผ๋กœ ๋˜์–ด์žˆ์œผ๋‹ˆ ๋ฒ„ํŠผ์„ ์‹คํ–‰ํ•˜๋ฉด ์ž๋™์œผ๋กœ form์„ ์„œ๋ฒ„์— ์ œ์ถœ
    //์ด๋•Œ ์ƒˆ๋กœ๊ณ ์นจ์ด ์ž๋™์œผ๋กœ ๋˜์–ด๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ๋ง‰๋Š” e.preventDefault()
    const onSubmit = (e) => {
        e.preventDefault();
        onInsertTodo(value);
        setValue(""); //๋นˆ๋ฌธ์ž์—ด๋กœ value๊ฐ’ ์ดˆ๊ธฐํ™”
        onInsertToggle(); //์ฐฝ ๋‹ค์‹œ ๋‹ซ์•„์ฃผ๊ธฐ
    };

    return (
        <div>
            <div className='background' onClick={onInsertToggle}></div> //๋ฐฐ๊ฒฝ์„ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ์ฐฝ ๋‹ซ๊ธฐ!
            <form onSubmit={onSubmit}>
                <input
                    placeholder='add your to-do'
                    value={value}
                    onChange={onChange}
                ></input>
                    <button type='submit'>
                        <MdAddCircle />
                    </button>
                )}
            </form>
        </div>
    );
};

export default TodoInsert;
โญ๏ธ ์™œ ์ƒˆ๋กœ์šด ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•  ๋•Œ, ๋ฐฐ์—ด์— push๊ฐ€ ์•„๋‹Œ concat์„ ์ผ์„๊นŒ?
setTodos((todos) => todos.concat(todo)); //์ƒํƒœ ๋ถˆ๋ณ€์„ฑ ์œ ์ง€ push ๋Œ€์‹  concat
push๋ฅผ ์“ฐ๋ฉด ๊ธฐ์กด๋ฐฐ์—ด ์ž์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€๋งŒ,
concat์„ ์“ฐ๋ฉด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฆฌํ„ดํ•˜๋˜ ๊ธฐ์กด ๋ฐฐ์—ด์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Œ!

ex) 
const arr1=[1,2,3,4]
arr1.push(5) //5
console.log(arr1) //[1,2,3,4,5]

const arr2=[1,2,3,4]
arr2.concat(5) //[1,2,3,4,5]
console.log(arr2) //[1,2,3,4]โ€‹

ํ•ด๋‹น ๊ธ€์„ ๋ˆ„๋ฅด๋ฉด checked๋œ ์ƒํƒœ๊ฐ’ ๋ณ€๊ฒฝํ•ด์ฃผ๊ธฐ (์™„๋ฃŒ/๋ฏธ์™„๋ฃŒ ์ƒํƒœ)

  • App.js
//์„ ํƒํ•œ id์™€ todos.id์˜ ๊ฐ’์ด ์ผ์น˜ํ•˜๋ฉด checked์ƒํƒœ๋งŒ ๋ฐ˜๋Œ€๋กœ ๋ฐ”๊ฟ”์ฃผ๊ธฐ
const onCheckToggle = (id) => {
        setTodos((todos) =>
            todos.map((todo) =>
                todo.id === id ? { ...todo, checked: !todo.checked } : todo
            )
        );
    };
    
    return (
        <Template todoLength={todos.length}>
            <TodoList
                todos={todos}
                onCheckToggle={onCheckToggle}
                onInsertToggle={onInsertToggle}
                onChangeSelectedTodo={onChangeSelectedTodo}
            />
...์ƒ๋žต

TodoList.js→TodoItem์œผ๋กœ onCheckToggle์„ props๋กœ ๊ณ„์† ์ „๋‹ฌํ•ด์ค€ ๋’ค, 

import React from "react";
import { MdCheckBox, MdCheckBoxOutlineBlank } from "react-icons/md";
import "./TodoItem.css";

const TodoItem = ({
    todo,
    onCheckToggle,
    onInsertToggle
}) => {
    const { id, text, checked } = todo;
    return (
        <div className='TodoItem'>
            <div className={`content ${checked ? "checked" : ""}`}>
                {checked ? (
                    <MdCheckBox
                        onClick={() => {
                            onCheckToggle(id);
                        }}
                    />
                ) : (
                    <MdCheckBoxOutlineBlank
                        onClick={() => {
                            onCheckToggle(id);
                        }}
                    />
                )}
                <div
                    className='text'
                    onClick={() => {
                        onInsertToggle();
                    }}
                >
                    {text}
                </div>
            </div>
        </div>
    );
};

export default TodoItem;
โญ๏ธ ์ด๋•Œ, onClick={onCheckToggle(id)}๋กœ ํ•˜๋ฉด ์•ˆ๋˜๊ณ , onClick={()=>onCheckToggle(id)} ํ˜•ํƒœ๋กœ ๋ณด๋‚ด์ค˜์•ผ๋ผ!

'DEV_IN > React' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

React Query  (2) 2023.03.24
React๋กœ TodoApp ๋งŒ๋“ค๊ธฐ (3)Delete,Update ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ  (2) 2023.03.02
React๋กœ TodoApp ๋งŒ๋“ค๊ธฐ (1)Setup  (4) 2023.03.02
JSX  (2) 2023.02.21
What is React?  (3) 2023.02.21
Comments