관리 메뉴

bright jazz music

todo-react-app(front) : fetch 이전 본문

Framework/ReactJs

todo-react-app(front) : fetch 이전

bright jazz music 2023. 5. 23. 16:34

 

App.js -> 추가 -> AddTodo.js -> Todo.js -> 수정/삭제/체크 -> 재 렌더링(App.js) 

 

 

// App.js

import "./App.css";
import Todo from "./Todo";
import AddTodo from "./AddTodo";
import React, { useState } from "react";
import { Paper, List, Divider, Container } from "@mui/material";

function App() {
  //기본 스테이트를 객체로 설정하였다.
  const [items, setItems] = useState([]);

  //Todo에서 쓰레기통 아이콘을 클릭하면 삭제된다. 이걸 <Todo>를 호출할 때 넣어준다. 위를 봐라.
  const deleteItem = (item) => {
    // 삭제할 item을 제외한 아이템을 다시 배열에 저장한다.
    const newItems = items.filter((e) => e.id !== item.id);
    console.log("##newItems", newItems);
    setItems([...newItems]);

    //여기가 문제네
    // const newItems = [];
    // for (let i = 0; i < items.length; i++) {
    //   if (items.id !== items[i]) {
    //     newItems.push(items[i]);
    //     // break;
    //   }
    // }
    // console.log("##newItems!!!", newItems);
    // setItems([...newItems]);
  };

  const editItem = () => {
    // items 내부의 값을 변경했기 때문에 새 배열로 초기화해 화면을 다시 렌더링한다.
    setItems([...items]);
  };

  // 실제 페이지에 나타나는 게시글 영역. paper영역에 목록이 나타난다. 여기서 쓰는 props는 이 함수 이전에 선언되어야 한다.
  let todoItems = items.length > 0 && (
    <Paper style={{ margin: 16 }}>
      <List>
        {items.map((item) => (
          <Todo
            item={item}
            key={item.id}
            //삭제
            deleteItem={deleteItem}
            //수정
            editItem={editItem}
          ></Todo>
        ))}
      </List>
    </Paper>
  );

  //AddTodo에서 "+" 버튼을 눌렀을 때 호출된다. 우선 AddTodo 컴포넌트에 넘기는 게 먼저이다.
  const addItem = (item) => {
    item.id = "ID-" + items.length; //key를 위한 id
    item.done = false; //done 초기화. 아이템을 추가하면 기본적으로 체크박스가 체크되지 않은 상태로 추가한다.
    //업데이트는 반드시 setItems로 하고 새 배열을 만들어야 한다.
    setItems([...items, item]);
    console.log("items: ", items);
  };

  return (
    <div className="App">
      <Container maxWidth="md">
        {/* AddTodo: Todo 추가, addItem도 props로 넘긴다. */}
        <AddTodo addItem={addItem}></AddTodo>
        {/* Todo 목록 표시 */}
        {todoItems}
      </Container>
    </div>
  );
}

export default App;

 

// Todo.js

import { CheckBox } from "@mui/icons-material";
import {
  InputBase,
  ListItem,
  ListItemText,
  Checkbox,
  Divider,
  ListItemSecondaryAction,
  IconButton,
} from "@mui/material";
// import { DeleteOutlined } from "@mui/icons-material/DeleteOutlined";
import { DeleteOutline } from "@mui/icons-material/";
import React from "react";
import { useState } from "react";

const Todo = (props) => {
  // function Todo(props) {
  const [item, setImte] = useState(props.item);
  const deleteItem = props.deleteItem;
  const editItem = props.editItem;

  const [readOnly, setReadOnly] = useState(true);

  // 아이템 삭제를 위한 함수 <IconButton> 에서 작동한다.
  const deleteEventHandler = () => {
    deleteItem(item);
  };

  const editEventHandler = (event) => {
    //이벤트의 변화가 props.item.title을 변경시킨다.
    item.title = event.target.value;
    console.log("##event.item.title", item.title);
    //App.js의 editItem()를 실행한다. setItems([...items])를 통해 재 렌더링하게 하여 바뀐 item 내용을 표시하도록 한다.
    editItem();
  };

  //turnOffReadOnly 함수 작성
  const turnOffReadOnly = () => {
    setReadOnly(false);
  };

  const turnOnReadOnly = (event) => {
    if (event.key === "Enter") {
      setReadOnly(true);
    }
  };

  const checkBoxEventHandler = (event) => {
    item.done = event.target.checked;
    console.log("##item.done", item.done);
    editItem();
  };

  return (
    <ListItem>
      {/** 체크박스: Box가 대문자가 아님에 주의. item.done의 기본값은 false. 체크하면 true로 바뀜. */}
      <Checkbox checked={item.done} onChange={checkBoxEventHandler}></Checkbox>
      {/* 체크박스 옆 텍스트 영역 */}
      <ListItemText>
        <InputBase
          inputProps={{ "aria-label": "naked", readOnly: readOnly }}
          //클릭하면 ReadOnly가 false로 바뀌면서 커서 점멸
          onClick={turnOffReadOnly}
          //Enter키 누르면 turnOnReadOnly 실행: ReadOnly가 true로 바뀜
          onKeyDown={turnOnReadOnly}
          //여기서의 변화가 event에 editEventHandler 함수로 전달
          onChange={editEventHandler}
          type="text"
          id={item.id}
          name={item.id}
          value={item.title}
          multiline={true}
          fullWidth={true}
        ></InputBase>
      </ListItemText>

      {/* 삭제버튼을 위한 구분 */}
      <ListItemSecondaryAction>
        {/* 아이콘 버튼에 함수를 연결한다. */}
        <IconButton aria-label="Delete Todo" onClick={deleteEventHandler}>
          {/* 삭제 아이콘 버튼*/}
          <DeleteOutline></DeleteOutline>
        </IconButton>
      </ListItemSecondaryAction>
    </ListItem>
  );

  //   return (
  //     <div className="Todo">
  //       <input type="checkbox" id={item.id} name={item.id} checked={item.done} />
  //       <label id={item.id}>{item.title}</label>
  //     </div>
  //   );
};

export default Todo;

 

// AddTodo.js

import React, { useState } from "react";
import { Button, Grid, TextField } from "@mui/material";

// function AddTodo(props) {
const AddTodo = (props) => {
  //사용자의 입력을 저장할 오브젝트
  const [item, setItem] = useState({ title: "" });
  const addItem = props.addItem;

  //onInputChange 함수 작성
  const onInputChange = (event) => {
    setItem({ title: event.target.value });
    console.log("##AddTodo-item", item);
  };

  const onButtonClick = () => {
    console.log("##AddTodo: onButtonClick 발동");
    addItem(item);
    // item을 다시 초기화 해준다. 이렇게 해주지 않으면 방금 추가된 내용이 item에 남기 때문이다.
    setItem({ title: "" });
  };

  //enterKeyEventHandler 함수: Enter키를 누르면 발동됨다
  const enterKeyEventhandler = (event) => {
    if (event.key === "Enter") {
      onButtonClick(); //괄호를 빼먹지 않도록 주의
    }
  };

  return (
    <Grid container style={{ marginTop: 20 }}>
      <Grid xs={11} md={11} item style={{ paddingRight: 16 }}>
        <TextField
          placeholder="Add Todo here"
          fullWidth
          onChange={onInputChange}
          //엔터키 입력 시 onKeyPress 발동
          onKeyPress={enterKeyEventhandler}
          value={item.title}
        ></TextField>
      </Grid>
      <Grid xs={1} md={1} item>
        <Button
          fullWidth
          style={{ height: "100%" }}
          color="secondary"
          variant="outlined"
          // 버튼클릭 시 onClick 발동 App.js addItem() 실행
          onClick={onButtonClick}
        >
          +
        </Button>
      </Grid>
    </Grid>
  );
};

export default AddTodo;
Comments