-
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 25WEB Dev/ToyProject 2022. 1. 13. 00:25728x90
๐ท 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'WEB Dev > ToyProject' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 27 (0) 2022.01.15 [ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 26 (0) 2022.01.13 [ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 24 (0) 2022.01.11 [ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 23 (0) 2022.01.06 [ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 22 (0) 2022.01.05