2022. 1. 2. 14:12ใWEB Dev/ToyProject
๐ท CloneTodo โ - Todomate Clone Project | Team CloneMate
CloneTodo : ๋ง์ ์ฌ๋๋ค์ด ์ฌ๋ํ๋ ํฌ๋๋ฉ์ดํธ๋ฅผ ํด๋ก ํ์ฌ ์น ์๋น์ค๋ฅผ ๋ฐฐํฌํด๋ณด๋ ํ๋ก์ ํธ
์ด์ ์ฆ๊ฑฐ์ด ๋งํฌ์ ์๊ฐ์ ๊ฐ๊ณ ์ง์ง ๊ธฐ๋ฅ๋ค์ ๊ตฌํํด๋์ผ ํ๋ ์์ ์ด ๋ ๊ฒ ๊ฐ๋ค.
์ด์ Main์ Feed ๋ถ๋ถ์ ๋ง๋ค์ด์ผ ํ๋๋ฐ, ์ด Feed๋ Goal(๋ชฉํ)์ ํ์์ ๋ค์ด๊ฐ๋ todo๋ฅผ ์ ๋ ฅํ๊ณ , ๊ด๋ฆฌํ๋ ๋ถ๋ถ์ด๋ผ Goal ํ์ด์ง ๋จผ์ ๋ง๋ค์ด์ผ ํ๋ค๋ ์ฌ์ค์ ๊นจ๋ฌ์๋ค.
์ด๋ฐ ์์๋ ์์ด ๋ง๊ตฌ์ก์ด๋ก ๋ง๋๋ ค๊ณ ํ๋ ์คํ๋ ค ๋ด Todo๊ฐ ์ ๋ฆฌ๊ฐ ์๋๋ ๋๋์ด๋ค.
๊ทธ๋์ ํํผ๋ก ๊ฐ๋์ฐจ๋ ๋ฐ๋์ ์ด์ ๋ ์กฐ๊ธ ์ฝ๋๋ฅผ ๊ฑด๋๋ ธ์ง๋ง ๊ธฐ๋ก์ ๋จ๊ธฐ์ง ๋ชปํด์ ์ค๋ ๋ชฐ์์ ๊ธฐ๋กํ๋ค.
์ฐ์ ์ฃผ๋ง ๊ณํ์ Goals โถ Feed ์์ผ๋ก ๊ธฐ๋ฅ ๊ตฌํ ๋ฐ CSS๋ฅผ ์ก๋ ๊ฒ์ด์๋ค..
ํฌ๋๋ฆฌ์คํธ์ด๋ ๋งํผ ์ฐ์ ์ด ๊ธฐ๋ฅ๋ค๋ง ๊ตฌํ์ด ๋๋ค๋ฉด ๊ฑฐ์ ์์ฑ์ด ๋ ๊ฒ์ด ์๋๊ฐ ์ถ์๋ฐ (์๋๋๋ค)
์ด๊ฑธ ๋์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ฒ์ ์ฐ๊ฒฐํ๋ ค๊ณ ํ๋ ์ฌ๋ฌ๋ชจ๋ก ๋ด๊ฐ ๋ณ๋๋ก ์๊ฐํ๊ณ ๊ณ ๋ฏผํ ๊ฒ์ด ๋ง์ ๊ฒ ๊ฐ์์
๊ฑฐ์ 90% ์ด์ ๊น๋ค์ ๋์ ์ฑ ์ ๊ธฐ๋ณธ์ผ๋ก ํ๋ ค๊ณ ํ๋ค.
์ฌ๊ธฐ์ ๋ฌธ์ ๋ ๊น๋ค์ ๋ ์ฑ ์ด ํด๋์คํ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ์ผ๋ก ๋์ด ์์ด์ return ์ดํ์ JSX๋ ์ฆ์ ์ ์ฉ์ด ๊ฐ๋ฅํ๋ฐ props-state ์ฐ๋ ๋ฐฉ์์ด ์ฐจ์ด๊ฐ ๋๋ค๋ ์ ์ด์๋ค.
์ด์จ๋ ์ด ์ฑ ์์ ์ ๊ณตํ๋ ๋ด์ฉ์ด ๋ด๊ฐ ๊ตฌํํด์ผ ํ๋ ํฌ๋๋ฆฌ์คํธ์ ๊ธฐ๋ฅ์ ๋ค๋ฃจ๊ณ ์์ผ๋ ํด๋์คํ์ ํจ์ํ์ผ๋ก ๋ฐ๊ฟ๊ฐ๋ฉด์ ๋ง๋ค์ด์ผ๊ฒ ๋ค.
1. Goals.js ๋ง๋ค๊ธฐ
'๋ชฉํ' ๋ฅผ ๋ง๋๋ ํ์ด์ง๋ฅผ ์์ฑํ๊ธฐ ์ํด Goals ๋ผ๋ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋ค.
import React from 'react';
import Box from '@mui/material/Box';
export default function Goals() {
return (
<Box className='goals-wrap' backgroundColor='#f66a5550' sx={{ position: 'relative' }}>
<input type='checkbox' id='todo0' name='todo0' checked='todo0' />
<label for='todo0'>'๋ชฉํ ๋ง๋ค๊ธฐ'</label>
</Box>
);
}
์๋ ํฌ๋๋ฉ์ดํธ์ goal์ ์ด๋ฐ ํ์ด์ง๋ค.
2. App.js์ State ๋ง๋ค๊ธฐ
์ํ๊ด๋ฆฌ Recoil์ ์ฐ๊ธฐ ์ , ํ๋ฉด์ ๊ตฌํํ๊ธฐ ์ํด ๋๋ฏธstate๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค.
App.js์ useState๋ฅผ import ํด์ค๋ค.
import React, { useState } from "react";
๊ทธ๋ฆฌ๊ณ ๋ ๋๋ง๋๋ App ํจ์ ๋ด๋ถ ์๋จ์
let [goal, goalChange] = useState({
id : 0,
title: '๋ชฉํ ๋ง๋ค๊ธฐ',
done: true
})
์ผ๋ก useState๋ฅผ ์ฌ์ฉํด State๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ , Route๋ฅผ ์ด์ฉํด url์ ํตํด Goals ์ปดํฌ๋ํธ๋ฅผ ๋ณผ ์ ์๊ฒ ํด์ค๋ค.
<Route exact path="/goals">
<BasicNavBar/>
<Goals />
</Route>
3. useState์ state props๋ก ์ ๋ฌํ๊ธฐ
Goals ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด๋๊ณ App.js์๋ค๊ฐ useState๋ฅผ ์ด์ฉํด ์ํ๋ฅผ ๋ง๋ ์ด์ ๋ ๋ฆฌ์กํธ์์ ๋ชจ๋ ์ํ๋ ์์์ ์๋๋ก ํ๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค.
๋์ค์ ์ด ์ํ๋ค์ Recoil์ด๋ผ๋ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด ์ ๋ฆฌ๊ฐ ๋ ๊ฑฐ์ง๋ง, state๋ props๋ผ๋ ์ด๋ฆ์ผ๋ก ์์์ ์๋๋ก ํ๋ฅด๋ ์ฑ๊ฒฉ ๋๋ฌธ์ ๋ด ์์ ๋ฌผ์ ๊ฐ์ฅ ์ต์๋จ ์ปดํฌ๋ํธ์ธ App.js์ ์ํ๋ฅผ ๋ง๋ค์ด์ ํ์ ์ปดํฌ๋ํธ์ ๋ณด๋ด๋ ๊ฒ์ด๋ค.
๋ฌผ๋ก ๋น์ฐํ Goals ์ปดํฌ๋ํธ์ state๋ฅผ ๋ง๋ค์ด๋ ๋์ง๋ง state๋ ์๋์์ ์๋ก๋ ๊บผ๋ด ์ธ ์ ์๋ค. ๊ทธ๋์ ํน์ ๋ชจ๋ฅด๊ฒ ๊ฐ์๊ธฐ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ด state๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด Goals์ ํ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ฃ์ง ์๋ ์ด์ ๊บผ๋ด ์ธ ์ ์๋ค.
๊ทธ๋์ ์์ ํ๊ฒ App๊ณผ ๊ฐ์ ์ต์์ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ์ ์ฅํ๋ค.
โจ ๋ฆฌ์กํธ์์์ ์ํ (State)
- ์ต์์์์ ์๋๋ก ์ ๋ฌ๋๋ค.
- ํ์ ์ปดํฌ๋ํธ์์ ์์ ์ปดํฌ๋ํธ๋ก ๋ชป ์ฌ๋ ค๋ณด๋ธ๋ค.
- ์์์์ ํ์๋ก ์ ๋ฌ๋ ๋๋ State๋ผ๋ ์ด๋ฆ์ด ์๋ Props๋ผ๋ ์ด๋ฆ์ ๊ฐ์ง๊ณ ๋ด๋ ค๊ฐ๋ค.
Route๋ก ๊ฐ์ผ goals์ปดํฌ๋ํธ์ props๋ก state๋ฅผ ์ ๋ฌํ๋ ๊ฒ์ ์๋์ ๊ฐ๋ค.
<Route exact path="/goals">
<BasicNavBar/>
<Goals id={goal.id} title={goal.title} done={goal.done} />
</Route>
props์ ํํ๋ ๋ง์น HTML์ Attribute(์์ฑ)๊ณผ ๊ฐ๋ค.
์ด๋ฆ = ๊ฐ ์ ํํ๋ก ๋ณด๋ด๋๋ฐ, ์์์ State์ ์ด๋ฆ์ goal๋ก ์ง์๊ณ , ๊ฐ์ฒด ํํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด์ ๊ฐ๋ณ ๊ฐ์ ๋ถ๋ฅด๋ ๋ฐฉ์์ธ .(์จ์ ) ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
๋ฐ๋ผ์ goal.id ํ๋ฉด id state๋ฅผ props ํํ๋ก ๋ณด๋ด๊ฒ ๋ค๋ ๊ฒ์ด๋ค.
์์ ์ ์ id=, title=, done=, ์ ์ด์ Goals ์ปดํฌ๋ํธ์์ props๋ฅผ ์ฌ์ฉํ๋ ์ด๋ฆ๋ค์ด ๋๋ค.
Goals ์ปดํฌ๋ํธ๋ ์๋์ ๊ฐ์ด props๋ก ์ํ๋ฅผ ๋ฐ์์ ํ๋ฉด์ ๋ฟ๋ ค์ค ์ ์๋ค.
import React from 'react';
import Box from '@mui/material/Box';
export default function Goals(props) {
return (
<Box className='goals-wrap' backgroundColor='#f66a5550' sx={{ position: 'relative' }}>
<input type='checkbox' id={props.id} name={props.id} checked={props.done} />
<label for={props.id}>{ props.title }</label>
</Box>
);
}
์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์ ์๋จ ํจ์ ์ ์ธ๋ถ์ ์ธ์๋ก props๋ฅผ ๋ฐ์์ค์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
์ ๊ฒ ์ ๋ค์ด๊ฐ ์์ผ๋ฉด ์์์์ ์๋ฌด๋ฆฌ props๋ฅผ ๋ณด๋ด๋ ์ธ์๋ก ๋ฐ์ง ์์ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ฅ ํจ์ ๊ฐ๋ ์ด๋ ๋๊ฐ๋ค. ๊ฐ์ ์๋ฌด๋ฆฌ ๋ณด๋ด๋ ์ธ์๊ฐ ์ง์ ๋์ง ์์ผ๋ฉด ํจ์๋ ์ ์๊ฐ ์๋ค.
๊ทธ๋ฆฌ๊ณ Goals ์ปดํฌ๋ํธ๊ฐ ๋ฆฌํดํ๊ณ ์๋ JSX์ ์์ input ๋ค์ ์์ฑ์ props.id ์์ผ๋ก props์ ์๋ id ๊ฐ์ ๊บผ๋ด์ค๊ฒ ๋ค ํ๊ณ ๋ฃ์ด์ค์ผ ํ๋ค. ๋ฌผ๋ก JSX์ ๋ณ์๋ { } ์ค๊ดํธ ์์ ๋ฃ์ด์ค์ผ ํ๋ค.
props๊ฐ ๋์ ์๋ณด์ฌ์ ํท๊ฐ๋ฆฌ๋ฉด ๋ ๊ทธ๋ ๋ฏ์ด console.log(props) ํด์ฃผ๋ฉด ์ดํดํ๋๋ฐ ๋์์ด ๋๋ค.
4. state๊ฐ ์ฌ๋ฌ๊ฐ๋ผ๋ฉด?
๋น์ฐํ ํ๋ฃจ์ ํ ๊ฐ์ Todo๋ง ๊ณํํ๋ ๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ ์ฌ๋ฌ๊ฐ์ todo๋ฅผ ๊ด๋ฆฌํด์ผ ํ ์๋ ์๋ค.
์๊น ๋ง๋ค์ด ๋์๋ state๊ฐ ์ฌ๋ฌ๊ฐ๋ผ๋ฉด ์ด๋ป๊ฒ ๋ฟ๋ ค์ผ ํ๋์ง ํ์ธํด๋ณด์.
์๊น ๋ง๋ goal์ด๋ผ๋ state๋ ์ด๋ ๊ฒ ์๊ฒผ๋ค.
let [goal, goalChange] = useState({
id : 0,
title: '๋ชฉํ ๋ง๋ค๊ธฐ',
done: true
})
์ด { id:0, title: '๋ชฉํ ๋ง๋ค๊ธฐ', done: true } ๊ฐ ์ฌ๋ฌ๊ฐ๋ผ๋ฉด ์ด๋ป๊ฒ ์๊ฒผ์๊น?
์ด ๋๋ ๊ทธ๋ฅ ๊ฐ์ฒด์ ๋์ด์ด ์๋ ๋ฐฐ์ด [ ] ์์ ๊ฐ์ฒด๋ฅผ ๋์ดํด์ค์ผํ๋ค.
๋ง๋ก ํ๋ฉด ์ด๋ ต๊ณ ๋ณด๋ฉด ์๋คใ ใ ์ด ๋ถ๋ถ์์ ๋๋ ์์ฒญ ํค๋ฉจ๋ค.
useState( [ {๊ฐ์ฒด0}, {๊ฐ์ฒด1}, {๊ฐ์ฒด2} ] ) ์ด๋ ๊ฒ ์์ฑํด์, ์ธ๋ฑ์ค๋ก ๊ฐ์ ธ๋ค ์ฐ๋ฉด ๋๋ค.
// ๋ชฉํgoals ํ์ด์ง goal ์์ดํ
let [goal, goalChange] = useState(
[
{
id : 0,
title: '๋ชฉํ ๋ง๋ค๊ธฐ',
done: true
},
{
id: 1,
title: '๋ชฉํ ๋ง๋ค๊ธฐ 2',
done: false
},
{
id: 2,
title: '๋ชฉํ ๋ง๋ค๊ธฐ 3',
done: false
},
]
)
์ด์ goal state๊ฐ ์ฌ๋ฌ๊ฐ๊ฐ ๋์์ผ๋ ๋ณด๋ด๋ props๋ ๊ฐ๊ฒฐํ๊ฒ ๋ฐ๊พธ๊ณ , Goals ์ปดํฌ๋ํธ์ input ๋ถ๋ถ๋ ๋ฐ๋ณต๋ฌธ์ ์ด์ฉํด์ ๋ชจ๋ props๋ฅผ ์ถ๋ ฅํ๋๋ก ๋ง๋ค์ด์ฃผ์.
// App.js
<Route exact path="/goals">
<BasicNavBar/>
<Goals goal={goal} />
</Route>
// Goals.js
import React from 'react';
import Box from '@mui/material/Box';
export default function Goals(props) {
let goalItems = props.goal;
return (
<Box className='goals-wrap' backgroundColor='#f66a5550' sx={{ position: 'relative' }}>
{goalItems.map((item, idx)=>{
return (
<>
<input type='checkbox' id={item.id} name={item.id} checked={item.done} />
<label for={item.id}>{ item.title }</label>
</>
)
})}
</Box>
);
}
props๋ฅผ ๋ฏธ๋ฆฌ goalItems๋ผ๋ ๋ณ์์ ๋ฃ์ด์ค๋ค. ๊ทธ๋ฌ๋ฉด goalItems๋ ๋ฐฐ์ด์ด๊ธฐ ๋๋ฌธ์ map() ์ผ๋ก ์ ๊ทผํ ์ ์๊ฒ ๋๋ค.
goalItems๋ฅผ map์ผ๋ก ๋๋ ค item์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฐ์์ฃผ๊ณ , map ํจ์๊ฐ return ํ๋ ๊ฐ์ JSX input ํ๊ทธ๋ค๋ก ๋ง๋ค์ด์ค๋ค. item ์ผ๋ก ๋ด์ฉ์ ๋ฐ์์ฃผ๊ณ ์๊ธฐ ๋๋ฌธ์ item.id, item.done, item.title์ด ๊ฐ attribute์ ๊ฐ์ด ๋๋ค.
๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
5. MUI๋ก UI ๋ง๋ค๊ธฐ
์ด์ ํ์ํ๊ฑด UI๋ฅผ ์ ๋ฆฌํ๋ ์ผ์ธ๋ฐ, ์ฑ ์์ ๋์จ ๊ฒ ์ฒ๋ผ MUI์ ListItem๊ณผ CheckBox, InputBase ๋ฑ์ ์ด์ฉํ๋ค.
import React from "react";
import { Checkbox, InputBase, ListItem, ListItemText } from "@mui/material";
export default function Goals(props) {
console.log(props.goal);
let goalItems = props.goal;
return (
<>
{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>
</ListItem>
);
})}
</>
);
}
๊ทธ๋ผ ์ด๋ ๊ฒ ๋ณํ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด ๋ค์์๋ ๋ชฉํ ์ถ๊ฐ ๊ธฐ๋ฅ์ ๋ง๋ค์ด์ผ ํ๋ค..!
'WEB Dev > ToyProject' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 22 (0) | 2022.01.05 |
---|---|
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 21 (0) | 2022.01.04 |
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 19 (0) | 2021.12.28 |
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 18 (0) | 2021.12.28 |
[ToyProject-Todomate] ํฌ๋๋ฉ์ดํธ ํด๋ก ํ๋ก์ ํธ 17 (0) | 2021.12.26 |