ABOUT ME

-

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


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

     

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

     


     

    ์–ด์ œ ๋งŒ๋“ค์–ด๋‘” ์ˆ˜์ • ํ•จ์ˆ˜๋ฅผ ์ด์–ด์„œ ๊ฐœ๋ฐœํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ ๋ณต์žกํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ ๋งŽ์ด ๋ง‰๋ง‰ํ•ด์กŒ๋‹ค.

    ํ•˜๋‚˜์”ฉ ์ •๋ฆฌํ•ด์„œ ํ’€์–ด๋‚˜๊ฐ€๋ณด์ž

     

     

    ๋ชฉํ‘œ ์ˆ˜์ • ๊ธฐ๋Šฅ์„ ์œ„ํ•ด ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๊ฒƒ

     

    - ํ˜„์žฌ ํ‘œ์‹œ๋œ ๋ชฉํ‘œ๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น state์˜ title๊ณผ key๊ฐ€ GoalForm์— ์ „๋‹ฌ๋  ๊ฒƒ

    - GoalForm์˜ textfield์— state์˜ title์ด ์ ํž ๊ฒƒ

    - title์„ ์ˆ˜์ •ํ•˜๊ณ  ๋‹ค์‹œ ๋“ฑ๋ก๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ฐ™์€ key์˜ state๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ๊ฒƒ

     

     

    ๊ทธ๋ฆฌ๊ณ  ๊ธฐ์กด์— ์ž‘์„ฑํ•œ ๋ชฉํ‘œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด๋ฉด InputBase๋กœ ์ ํ˜€์žˆ๋Š”๋ฐ ์ด๊ฒŒ ๊ทธ๋ƒฅ list ๊ฐ™์€ ํƒœ๊ทธ๊ฐ€ ์•„๋‹ˆ๋ผ์„œ

    readOnly๊ฐ€ ํ•„์š”ํ–ˆ๋˜ ๊ฒƒ์ด์—ˆ๋‹ค.

     

    ๊ธฐ์กด์— ๋งŒ๋“ค์—ˆ๋˜ ์ˆ˜์ • ํ•จ์ˆ˜์™€ readOnly state๋ฅผ ์‚ญ์ œํ•˜๊ณ  ๋‹ค์‹œ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ๋ณด์ž.

    ๊ทธ๋ฆฌ๊ณ  ListItem ์•ˆ์— InputBase๋ฅผ Label๋กœ ๋ฐ”๊ฟ”์„œ ์ฒดํฌ๋ฐ•์Šค๊ฐ€ ์ฒดํฌ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์ž.

     

     

     

     

    ์œ„์˜ Label ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ™•์ธํ•˜๊ณ  ๊ฐ™์€ ๋ชจ์–‘์œผ๋กœ Goals.js ๋ฅผ ๋ฐ”๊ฟ”์ค€๋‹ค.

    Label์„ ์„ ํƒํ•œ ์ด์œ ๋Š” ๋‚˜์ค‘์— todomate์ฒ˜๋Ÿผ ๋ชฉํ‘œ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ฒดํฌ๋ฐ•์Šค๊ฐ€ ์ฒดํฌ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค.

    label ์†์„ฑ์— item.title์ด ๋“ค์–ด๊ฐ€๋ฉด ๋˜๊ฒ ๋‹ค.

     

    checked ์†์„ฑ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— item.done์˜ ๊ฐ’๋„ checked๋กœ ๋ณ€๊ฒฝํ•ด์ค€๋‹ค.

     

     

    <Checkbox
      checked={checked}
      onChange={handleChange}
      inputProps={{ 'aria-label': 'controlled' }}
    />

     

      // ๋ชฉํ‘œgoals ํŽ˜์ด์ง€ goal ์•„์ดํ…œ
      let [goal, goalChange] = useState(
         { 
           items: [{
           id: '0',
           title: '์ฒซ๋ฒˆ์งธ',
           done: 'checked',
            },
            { id: '1',
              title: '๋‘๋ฒˆ์งธ',
              done: '',
          }]
        }
      )

     

     

    state๋ฅผ ์œ„์™€ ๊ฐ™์ด ๋ฐ”๊พธ๊ณ  Goals.js ์ปดํฌ๋„ŒํŠธ๋„ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ–ˆ๋‹ค.

     

     

    import React from "react";
    import { Checkbox, FormControlLabel, FormGroup, 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);
      let goalItems = props.goal;
      let addGoal = props.addGoal;
      let deleteGoal = props.deleteGoal;
      let checkboxEventHandler = props.checkboxEventHandler;
    
    
      //๋ชฉํ‘œ ์‚ญ์ œ ์ด๋ฒคํŠธํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜
    
        function deleteEventHandler(e) {
          console.log( 'id : ',  e.target.id)
          deleteGoal(e.target.id, goalItems)
        }
    
    
      return (
        <FormGroup>
        <GoalForm addGoal={addGoal} />
    
            {
            goalItems.map((item, idx) => {
             
            return ( <ListItem className="goals-wrap" key={item.id} > { console.log('item: ', item) }
                        <ListItemText>
                        <FormControlLabel control={<Checkbox checked={item.done} onChange={checkboxEventHandler} />}
                        id={item.id}
                        name={item.id}
                        label={item.title}
                        fullWidth={true}
                        
                        />
                        </ListItemText>
                        <ListItemSecondaryAction>
                        <IconButton aria-label="Delete Todo" id={item.id} onClick={deleteEventHandler} sx={{ fontSize: '14px' }}>
                            ์‚ญ์ œ
                        </IconButton>
                        </ListItemSecondaryAction>
                    </ListItem>
                    );
                })
            }
        </FormGroup>
      );
    }

     

     

    ๋ชจ์–‘์€ ์˜ˆ์˜๊ฒŒ ์ž˜ ๋‚˜์™”๋Š”๋ฐ... ์ •์‹ ์ฐจ๋ ค๋ณด๋‹ˆ ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” '๋ชฉํ‘œ' ๋Š” ๊ทธ์•ผ๋ง๋กœ ๋ชฉํ‘œ๊ณ  

    ์‹ค์ œ๋กœ๋Š” ์ฒดํฌ๋ฐ•์Šค์˜ ๊ธฐ๋Šฅ์„ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์žˆ์—ˆ๋‹ค.

     

     

    ํด๋ก ํ•˜๋Š” ์›๋ณธ์˜ ๊ธฐ๋Šฅ๋„ ์ œ๋Œ€๋กœ ํŒŒ์•…์„ ๋ชปํ–ˆ๋‹ค๋Š”๊ฒŒ ๋„ˆ๋ฌด ์–ด์ด์—†์—ˆ๋‹ค.

     

     

    ์œ„์˜ Goals.js ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณ€๊ฒฝํ•ด๋ณด์ž

     

     

    import React from "react";
    import {  IconButton, List, ListItem  } from "@mui/material";
    import GoalForm from "./GoalForm";
    import { ListItemText } from "@material-ui/core";
    
    export default function Goals(props) {
      console.log(props);
      let goalItems = props.goal;
      let addGoal = props.addGoal;
      let deleteGoal = props.deleteGoal;
    
      /* ํ•จ์ˆ˜ ์‹œ์ž‘ */
    
      //๋ชฉํ‘œ ์‚ญ์ œ ์ด๋ฒคํŠธํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜
    
        function deleteEventHandler(e) {
          console.log( 'id : ',  e.target.id)
          deleteGoal(e.target.id, goalItems)
        }
    
    /* ํ•จ์ˆ˜ ๋ */
    
    
      return (
        <>
        <GoalForm addGoal={addGoal} />
        <List>
            {
            goalItems.map((item, idx) => {
             
            return ( <ListItem className="goals-wrap" id={item.id} key={item.id}  > 
                        <ListItemText>{item.title} </ListItemText>
                        <IconButton aria-label="Delete Todo" id={item.id} onClick={deleteEventHandler} sx={{ fontSize: '14px' }}>
                            ์‚ญ์ œ
                        </IconButton>
                    </ListItem>
                    );
                })
            }
        </List>
        </>
      );
    }

     

     

    ์ด๋ ‡๊ฒŒ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค.

    ์‚ญ์ œ ๋ฒ„ํŠผ์˜ onClick ํ•ธ๋“ค๋Ÿฌ๋Š” ๊ทธ๋Œ€๋กœ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๊ณ , props๋กœ ๋‚ด์šฉ์€ ์ž˜ ๊ฐ€์ง€๊ณ  ์˜ค๊ณ  ์žˆ์œผ๋‹ˆ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

    Goal state์—์„œ done์„ ์‚ญ์ œํ•ด์ฃผ๋ฉด ๋˜๊ฒ ๋‹ค!

     

     

      // ๋ชฉํ‘œgoals ํŽ˜์ด์ง€ goal ์•„์ดํ…œ
      let [goal, goalChange] = useState(
         { 
           items: [{
           id: '0',
           title: '์ฒซ๋ฒˆ์งธ',
            },
            { id: '1',
              title: '๋‘๋ฒˆ์งธ',
          }]
        }
      )

     

     

    ๊ทธ๋Ÿผ ์ž…๋ ฅ๋„ ์ •์ƒ์ ์œผ๋กœ ๋  ์ˆ˜ ์žˆ๋„๋ก addGoal ํ•จ์ˆ˜๋„ ์ˆ˜์ •ํ•œ๋‹ค.

    item.done์ด ์ƒ์„ฑ๋˜์ง€ ์•Š๋„๋ก ์ง€์›Œ์ฃผ๊ณ , readOnly ๊ด€๋ จ ํ•จ์ˆ˜๋„ ์‚ญ์ œํ•ด App.js ๋ฅผ ์ „์ฒด ์ˆ˜์ •ํ•œ๋‹ค.

     

     

     

    import React, { useState } from "react";
    import "../stylesheets/App.css";
    import { Button  } from "@mui/material";
    import { ThemeProvider, createTheme } from "@mui/material/styles";
    import { Switch, Route, useHistory } from "react-router-dom";
    import Signin from "./Signin";
    import Join from "./Join";
    import BasicNavBar from "./BasicNavBar";
    import Goals from "./Goals";
    import Main from "./Main";
    
    
    const theme = createTheme({
      components: {
        MuiTypography: {
          defaultProps: {
            variantMapping: {
              h1: 'h2',
              h2: 'h2',
              h3: 'h2',
              h4: 'h2',
              h5: 'h2',
              h6: 'h2',
              subtitle1: 'h2',
              subtitle2: 'h2',
              body1: 'span',
              body2: 'span',
            },
          },
        },
      },
      typography: {
        Link: {
          color: '#222',
        },
        bolder: {
          fontWeight: 600,
        },
        button: {
    
        },
      },
      palette: {
        btn: {
          main: "#f2f2f2",
          contrastText: "#111",
        },
        basicnav: {
          main: "#fefefe",
          contrastText: "#111",
        },
        mainnav: {
          main: '#FAFAFA'
        },
        main: {
          main: '#e4f2b4'
        },
        content: {
          main: '#23fa43'
        },
        explore: {
          main: '#2a5dc9'
        },
        feed: {
          main: '#f66a55'
        },
        calendar: {
          main: '#9f4cd6'
        },
      },
    });
    
    function App() {
      
      /* Hook ์„ ์–ธ ์‹œ์ž‘ */
      
      let history = useHistory();
    
      /* Hook ์„ ์–ธ ๋ */
    
    
      /* Dummy State ์‹œ์ž‘ */
    
      // ๋ชฉํ‘œgoals ํŽ˜์ด์ง€ goal ์•„์ดํ…œ
      let [goal, goalChange] = useState(
         { 
           items: [{
           id: '0',
           title: '์ฒซ๋ฒˆ์งธ',
            },
            { id: '1',
              title: '๋‘๋ฒˆ์งธ',
          }]
        }
      )
    
      /* Dummy State ๋ */
    
    
      /* ํ•จ์ˆ˜ ์„ ์–ธ ์‹œ์ž‘ */
    
    
      //๋ชฉํ‘œ ์ถ”๊ฐ€ ํ•จ์ˆ˜
      function addGoal(item){
    
        const thisItems = goal.items; // goal State ์›๋ณธ ์นดํ”ผ
        item.id = 'ID-' + thisItems.length; //key๋ฅผ ์œ„ํ•œ id ์ถ”๊ฐ€
        thisItems.push(item) // ์นดํ”ผํ•œ goal ๋ฆฌ์ŠคํŠธ์— ์•„์ดํ…œ ์ถ”๊ฐ€
        goalChange({items: thisItems}); //goalChange๋ฅผ ์ด์šฉํ•ด state ๋ณ€๊ฒฝ
        console.log('items :', goal.items)
      }
    
      //๋ชฉํ‘œ ์‚ญ์ œ ํ•จ์ˆ˜
      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})
      }
    
      /* ํ•จ์ˆ˜ ์„ ์–ธ ๋ */
    
    
      return (
        <ThemeProvider theme={theme}>
          <Switch>
            <Route exact path="/">
              <div className="App">
                <div className="header">
                  <img className="main_img" src="images/todomate.jpg" />
                  <h1>todo mate</h1>
                  <h3>ํ•  ์ผ์„ ์ž‘์„ฑ, ๊ณ„ํš, ๊ด€๋ฆฌํ•˜์„ธ์š”.</h3>
                </div>
                <div className="start_btn">
                  <Button 
                    className="join_btn" 
                    color="btn"
                    variant="contained" 
                    sx={{ boxShadow: 'none'}}
                    onClick={() => {
                      history.push("/join");
                    }}
                  >
                    ๊ฐ€์ž…ํ•˜๊ธฐ
                  </Button>
                  <Button
                    className="signin_btn"
                    color="btn"
                    variant="contained"
                    sx={{ boxShadow: 'none'}}
                    onClick={() => {
                      history.push("/signin");
                    }}
                  >
                    ๋กœ๊ทธ์ธ
                  </Button>
                </div>
              </div>
            </Route>
            <Route exact path="/main">
              <Main/>
            </Route>
            <Route exact path="/join">
            <BasicNavBar/>
              <Join />
            </Route>
            <Route exact path="/signin">
            <BasicNavBar/>
              <Signin />
            </Route>
            <Route exact path="/goals">
            <BasicNavBar/>
              <Goals goal={goal.items} addGoal={addGoal} deleteGoal={deleteGoal} />
            </Route>
            </Switch>
        </ThemeProvider>
      );
    }
    
    export default App;

     

     

     

    ์ง„์ž‘ ์ด๋ ‡๊ฒŒ ํ• ๊ฑธ ^^

     

     

    ๊ทธ๋Ÿผ ์ด์ œ ๋“œ๋””์–ด ์ˆ˜์ •์„ ๊ตฌํ˜„ํ•ด๋ณด์ž;

     

    728x90

    ๋Œ“๊ธ€

Designed by Tistory.