ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ToyProject-Todomate] ํˆฌ๋‘๋ฉ”์ดํŠธ ํด๋ก  ํ”„๋กœ์ ํŠธ 22
    WEB Dev/ToyProject 2022. 1. 5. 00:10
    728x90


    ๐Ÿ”ท CloneTodo โ˜‘ - Todomate Clone Project  |  Team CloneMate

     

    CloneTodo : ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ๋ž‘ํ•˜๋Š” ํˆฌ๋‘๋ฉ”์ดํŠธ๋ฅผ ํด๋ก ํ•˜์—ฌ ์›น ์„œ๋น„์Šค๋ฅผ ๋ฐฐํฌํ•ด๋ณด๋Š” ํ”„๋กœ์ ํŠธ

     


     

    ์˜ค๋Š˜ ํ•  ์ผ์€ ์ฑ…์— ๋‚˜์˜จ๋Œ€๋กœ Todo๋ฅผ ์‚ญ์ œํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณธ๋‹ค. ํˆฌ๋‘๋ฉ”์ดํŠธ์—์„œ์˜ ๋ชฉํ‘œ ์‚ญ์ œ ๋ฒ„ํŠผ์€ ํ•˜๋‹จ์— ์žˆ๊ณ , ํด๋ฆญํ•˜๋ฉด ์ž‘์„ฑํ•œ ๋ชฉํ‘œ๊ฐ€ ์‚ญ์ œ๋œ๋‹ค. 

    ์š”๊ฒƒ์€ ๋‚˜์ค‘์˜ ์ž๋ฆฌ๋ฐฐ์น˜์˜ ๋ฌธ์ œ์ผ ๊ฒƒ ๊ฐ™์•„์„œ ์šฐ์„  ํ›„๋”ฑ ์‚ญ์ œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค.

     

    MUI์˜ ListItemSecondaryAction์„ ์ด์šฉํ•ด์„œ ์‚ญ์ œ ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•œ๋‹ค. ์ด ๋•Œ ์‚ญ์ œ ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋“ค์–ด๊ฐˆ ๊ณณ์€ ์ด์ „์— ๋งŒ๋“  Goals.js ์ปดํฌ๋„ŒํŠธ์˜ <ListItem> </ListItem> ์‚ฌ์ด๊ฐ€ ๋˜๊ฒ ๋‹ค. 

    ๊ทธ๋ฆฌ๊ณ  InputBase์— id์™€ name ์†์„ฑ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์ด id์™€ name์ด ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•  ๋•Œ ์–ด๋–ค ๋ชฉํ‘œ๋ฅผ ์ง€์ •ํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด ์ค„ ์ˆ˜ ์žˆ๋Š” ํ‚ค๊ฐ€ ๋œ๋‹ค.

    import React from "react";
    import { Checkbox, IconButton, InputBase, ListItem, ListItemText } from "@mui/material";
    import GoalForm from "./GoalForm";
    import { ListItemSecondaryAction } from "@material-ui/core";
    
    export default function Goals(props) {
      console.log(props.goal);
      let goalItems = props.goal;
      let add = props.add;
      return (
        <>
        <GoalForm add={add} />
    
            {
            goalItems.map((item, idx) => {
            return (
                    <ListItem className="goals-wrap">
                        <Checkbox checked={item.done} />
                        <ListItemText>
                        <InputBase
                            inputProps={{ "aria-label": "naked" }}
                            type="text"
                            id={item.id}
                            name={item.id}
                            value={item.title}
                            multiline={true}
                            fullWidth={true}
                        />
                        </ListItemText>
                        <ListItemSecondaryAction>
                        <IconButton aria-label="Delete Todo" sx={{ fontSize: '14px' }}>
                            ์‚ญ์ œ
                        </IconButton>
                    </ListItemSecondaryAction>
                    </ListItem>
                    );
                })
            }
        </>
      );
    }

     

    ์›๋ž˜ ์•„์ด์ฝ˜์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๋‚˜๋Š” ์‚ญ์ œ ๋ผ๊ณ  ์ ํžŒ ๊ธด ๋ฒ„ํŠผ์œผ๋กœ ๋ณ€ํ™˜ํ•  ์˜ˆ์ •์ด๋ผ ์‚ญ์ œ๋ผ๋Š” ํ…์ŠคํŠธ๋กœ ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค. 

     

    ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ–ˆ์œผ๋‹ˆ ์ด์ œ ์‚ญ์ œ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค. delete() ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ๊ฑด๋ฐ, ํ˜„์žฌ state๋ฅผ ์‚ญ์ œํ•ด์•ผํ•˜๊ณ , state๋Š” app.js ์— ์žˆ์œผ๋‹ˆ app.js๋กœ ๊ฐ€์„œ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๊ณ  props๋กœ ๋„˜๊ฒจ์ค˜์•ผ ํ•œ๋‹ค. add์™€ ๊ฐ™๋‹ค. 

    delete ๋ผ๊ณ  ํ•จ์ˆ˜์ด๋ฆ„์„ ์ž‘์„ฑํ•˜๋ฉด ์˜ˆ์•ฝ์–ด๋ผ๊ณ  ์•ˆ๋œ๋‹ค๊ณ  ํ•œ๋‹ค. deleteGoal๋ผ๋Š” ํ•จ์ˆ˜์ด๋ฆ„์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๊ณ , add๋„ ๋™์ผํ•˜๊ณ  addGoal ๋กœ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ๋ฐ”๊ฟ”์ค€๋‹ค.

     

    //app.js ์— ์ž‘์„ฑ
    
    
      //๋ชฉํ‘œ ์ถ”๊ฐ€ ํ•จ์ˆ˜
      function addGoal(item){
    
        const thisItems = goal.items; // goal State ์›๋ณธ ์นดํ”ผ
        item.id = 'ID-' + thisItems.length; //key๋ฅผ ์œ„ํ•œ id ์ถ”๊ฐ€
        item.done = false; // done false๋กœ ์ดˆ๊ธฐํ™”
        thisItems.push(item) // ์นดํ”ผํ•œ goal ๋ฆฌ์ŠคํŠธ์— ์•„์ดํ…œ ์ถ”๊ฐ€
        goalChange({items: thisItems}); //goalChange๋ฅผ ์ด์šฉํ•ด state ๋ณ€๊ฒฝ
        console.log('items :', goal.items)
      }
    
      //๋ชฉํ‘œ ์‚ญ์ œ ํ•จ์ˆ˜
      function deleteGoal(item){
    
        const thisItems = goal.items;
        console.log('Before Update Items :', goal.items );
        const newItems = thisItems.filter(e => e.id !== item.id)
        goalChange({items: newItems},()=>{
          console.log('Update Items : ', goal.items)
        })
      }

     

    ๋ชฉํ‘œ ์‚ญ์ œ ํ•จ์ˆ˜๋Š” Goals ์ปดํฌ๋„ŒํŠธ์— ๋ณด๋‚ด์ ธ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Goals ์ปดํฌ๋„ŒํŠธ์— props๋กœ ๋ณด๋‚ด์ค€๋‹ค.

            <Route exact path="/goals">
            <BasicNavBar/>
              <Goals goal={goal.items} add={addGoal} delete={deleteGoal} key={goal.items.id} />
            </Route>

     

    ์ด์ „์— add ํ•จ์ˆ˜๋Š” Goals ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ›์•„์„œ GoalForm์œผ๋กœ ํ•œ ๋ฒˆ ๋” ์ „๋‹ฌํ–ˆ๋Š”๋ฐ, ์ด๋ฒˆ์—” ๋ฐ”๋กœ props๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Goals.js์— ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ค€๋‹ค. 

     

        function deleteEventHandler() {
            props.delete(goalItems)
        }
    
    //์—ฌ๊ธฐ์„œ goalItems๋Š” ์ €๋ฒˆ์— props.goal์„ ๋ฐ›์•„๋‘” ๋ณ€์ˆ˜์ด๋‹ค.

     

    ์ด์ œ ์ด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์•„๊นŒ ๋งŒ๋“ค์–ด ๋‘” ์‚ญ์ œ ๋ฒ„ํŠผ์— ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด ๋œ๋‹ค. 

     

    //Goals.js
    
    import React from "react";
    import { Checkbox, IconButton, InputBase, ListItem, ListItemText } from "@mui/material";
    import GoalForm from "./GoalForm";
    import { ListItemSecondaryAction } from "@material-ui/core";
    
    export default function Goals(props) {
      console.log(props.goal);
      let goalItems = props.goal;
      let add = props.add;
    
        function deleteEventHandler() {
            props.delete(goalItems)
        }
    
      return (
        <>
        <GoalForm add={add} />
    
            {
            goalItems.map((item, idx) => {
            return (
                    <ListItem className="goals-wrap">
                        <Checkbox checked={item.done} />
                        <ListItemText>
                        <InputBase
                            inputProps={{ "aria-label": "naked" }}
                            type="text"
                            id={item.id}
                            name={item.id}
                            value={item.title}
                            multiline={true}
                            fullWidth={true}
                        />
                        </ListItemText>
                        <ListItemSecondaryAction>
                        <IconButton aria-label="Delete Todo" onClick={deleteEventHandler} sx={{ fontSize: '14px' }}>
                            ์‚ญ์ œ
                        </IconButton>
                    </ListItemSecondaryAction>
                    </ListItem>
                    );
                })
            }
        </>
      );
    }

     

    ๋‹ค ๋งŒ๋“ค์–ด๋†“๊ณ  ์‹คํ–‰ํ•ด๋ณด๋‹ˆ ๋ชฉํ‘œ๊ฐ€ ์‚ญ์ œ๋„ ์•ˆ๋˜๊ณ  ์ฝ˜์†”์—๋Š” 

    index.js:1 Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().

     

    ์ด๋Ÿฐ ๋ฉ”์‹œ์ง€๊ฐ€ ๋–ด๋‹ค. useState์˜ ๋ณ€๊ฒฝ ํ•จ์ˆ˜์— ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์“ฐ์ง€ ๋ง๋ผ๋Š” ์ด์•ผ๊ธฐ ๊ฐ™์€๋ฐ (...) ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚ด๋ง˜๋Œ€๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๊ทธ๋Ÿฐ๊ฐ€๋ณด๋‹ค. goalChange ํ•จ์ˆ˜์—์„œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋นผ์ฃผ์ž. ์›๋ž˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋„ ๋””๋ฒ„๊น… console.log๋ฅผ ์ฐ๋Š”๊ฑฐ๋ผ ํฐ ๋ฌธ์ œ๋Š” ์—†์„ ๋“ฏ ํ•˜๋‹ค. 

     

    ๊ทธ๋ฆฌ๊ณ  ์‚ญ์ œ๊ฐ€ ์•ˆ๋˜๋Š”๊ฑด ....

    ์™œ์ผ๊นŒ? ํ•จ์ˆ˜ ์ด๋ฒคํŠธ๋Š” ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์•„ ๋ฐ”์ธ๋”ฉ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๋Š”๋ฐ, id ๊ฐ’์„ ๋น„๊ตํ•˜๋Š”๋ฐ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๋‹ค๋ฅธ ๋ฌธ์„œ๋“ค์„ ๋” ์ฐพ์•„๋ณด๊ณ  ํ•จ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค. ์•„๋‹˜ ๋‚ด๊ฐ€ ๋ญ”๊ฐ€ ์ž˜๋ชป ์ž‘์„ฑํ•œ๊ฑธ๊นŒใ… ใ… 

     

      //๋ชฉํ‘œ ์‚ญ์ œ ํ•จ์ˆ˜
      function deleteGoal(item){
    
        const thisItems = goal.items; // goal State ์›๋ณธ ์นดํ”ผ
        console.log('Before Update Items :', goal.items );
        const newItems = thisItems.filter(e => e.id !== item.id)
        goalChange({items: newItems}, console.log('update : ' , newItems)
        )
      }

     

    ์–ด๋”” ๋ฌผ์–ด๋ณผ๋ฐ๊ฐ€ ์—†์œผ๋‹ˆ ๋‹ต๋‹ตํ•˜๊ธฐ๋งŒ ํ•˜๋‹คใ… ใ… 

     

     

     

     

    e.id๋ž‘ item.id๋ฅผ ์ฐ์–ด๋ณด๋‹ˆ ๋‘˜ ๋‹ค undefined๋‹ค..

    ๋ญ”๊ฐ€ e.id๊ฐ€ ์ œ๋Œ€๋กœ ์•ˆ ๋“ค์–ด๊ฐ€๊ณ  ์žˆ๋˜์ง€ item.id๊ฐ€ ์•ˆ๋“ค์–ด๊ฐ€๋Š”๊ฑฐ ๊ฐ™์€๋ฐ ์šฐ์„  add ํ•จ์ˆ˜ ๋•Œ ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ onClick์ด๋ฒคํŠธ์— deleteEventHandler์— e๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ ํ•ด๋‹น IconButton์— id ์†์„ฑ์„ ๋„ฃ์–ด์ฃผ๊ณ , id๋ฅผ deleteGoal ํ•จ์ˆ˜๋กœ ๋ณด๋‚ด์ฃผ์—ˆ๋‹ค.

     

    <IconButton aria-label="Delete Todo" id={item.id} onClick={deleteEventHandler} sx={{ fontSize: '14px' }}>
    ์‚ญ์ œ
    </IconButton>
        function deleteEventHandler(e) {
          console.log( 'id : ',  e.target.id)
          props.deleteGoal(e.target.id, goalItems)
        }

     

    ๊ทธ๋ฆฌ๊ณ  deleteGoal ํ•จ์ˆ˜์— ์ธ์ž๋ฅผ ๋‘ ๊ฐœ ๋ฐ›๋„๋ก ํ•ด์„œ ํด๋ฆญํ•œ list์˜ id ๊ฐ’๊ณผ goal state๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

      //๋ชฉํ‘œ ์‚ญ์ œ ํ•จ์ˆ˜
      function deleteGoal(targetId, item){
    
        const thisItems = item; // goal State ์›๋ณธ ์นดํ”ผ
        console.log('Before Update Items :', item );
        const newItems = thisItems.filter(e => e.id !== targetId)
        goalChange({items: newItems})
      }

     

    ์ด๋ ‡๊ฒŒ ํ•˜๋‹ˆ ์‚ญ์ œ๊ฐ€ ๋œ๋‹ค... ๊ฐ๋™ ใ… ใ… ใ… ใ… ใ… ใ… 

    ์ •ํ™•ํ•˜๊ฒŒ ๋ญ๊ฐ€ ๋”ฑ ํ‹€๋ ค์„œ ๊ทธ๋žฌ๋‹ค! ์„ค๋ช…ํ•˜๊ธฐ๋Š” ์–ด๋ ค์šด๋ฐ ์ด๋ ‡๊ฒŒ ํ•ด๊ฒฐํ•˜๊ณ  ๋‚˜๋‹ˆ ๋ญ”๊ฐ€ ๊ตฌ์กฐ๋ฅผ ์•Œ๊ฒŒ๋œ ๊ฑฐ ๊ฐ™๊ณ  ๋ฟŒ๋“ฏํ•˜๊ธฐ๋งŒ ํ•˜๋‹ค.... ์˜ค๋Š˜์€ ํŽธํ•˜๊ฒŒ ์ž ๋“ค ์ˆ˜ ์žˆ๊ฒ ๋‹ค...

     

     

    728x90

    ๋Œ“๊ธ€

Designed by Tistory.