📅2024. 04. 08 81일차
최초 구조
NewTodoForm, TodoList로 나뉨
TodoList에서 TodoListItem 분리
OptionDrawer와 EditTodoModal 추가
NoticeSnackbar 추가
상태관리 툴 x, 직접 자식 엘리먼트에 전달
상태관리 툴 o, 필요한 엘리먼트에서 상태를 직접 주입받는다
import { RecoilRoot, atom, selector, useRecoilState, useRecoilValue } from 'recoil';
const todosAtom = atom({
key: 'app/todosAtom',
default: [],
});
function useTodosStatus() {
const [todos, setTodos] = React.useState([]);
const [todos, setTodos] = useRecoilState(todosAtom);
// const [todos, setTodos] = React.useState([]);
//생략
//생략
export default function themeApp() {
const theme = RootTheme();
return (
<RecoilRoot>
<ThemeProvider theme={theme}>
<CssBaseline />
<App />
</ThemeProvider>
</RecoilRoot>
);
}
const lastTodoIdAtom = atom({
key: 'app/lastTodoIdAtom',
default: 0,
});
//생략
function useTodosStatus() {
const [todos, setTodos] = useRecoilState(todosAtom);
// const [todos, setTodos] = React.useState([]);
const lastTodoIdRef = React.useRef(0);
const [lastTodoId, setLastTodoId] = useRecoilState(lastTodoIdAtom);
const lastTodoIdRef = React.useRef(lastTodoId);
//생략
const todosAtom = atom({
key: 'app/todosAtom',
default: [],
});
const lastTodoIdAtom = atom({
key: 'app/lastTodoIdAtom',
default: 0,
});
function useTodosStatus() {
const [todos, setTodos] = useRecoilState(todosAtom);
// const [todos, setTodos] = React.useState([]);
const [lastTodoId, setLastTodoId] = useRecoilState(lastTodoIdAtom);
const lastTodoIdRef = React.useRef(lastTodoId);
lastTodoIdRef.current = lastTodoId;
//생략
function App() {
const todosStatus = useTodosStatus();
const noticeSnackbarStatus = useNoticeSnackbarStatus();
React.useEffect(() => {
todosStatus.addTodo('스쿼트\n런지');
todosStatus.addTodo('벤치');
todosStatus.addTodo('데드');
}, []);
return (
<>
<AppBar position="fixed">
<Toolbar>
<div className="tw-flex-1">
<FaBars onClick={() => setOpen(true)} className="tw-cursor-pointer" />
</div>
<div className="logo-box">
<a href="/" className="tw-font-bold">
TODO!
</a>
</div>
<div className="tw-flex-1 tw-flex tw-justify-end">
<a href="/write">글쓰기</a>
</div>
</Toolbar>
</AppBar>
<Toolbar />
<NoticeSnackbar status={noticeSnackbarStatus} />
<NewTodoForm noticeSnackbarStatus={noticeSnackbarStatus} />
<TodoList todosStatus={todosStatus} noticeSnackbarStatus={noticeSnackbarStatus} />
</>
);
}
const NewTodoForm = ({ noticeSnackbarStatus }) => {
const todosStatus = useTodosStatus();
localStorage
사용자가 데이터를 지우지 않는 이상, 브라우저나 OS를 종료해도 계속 브라우저에 남아있음 (영구성)
단, 동일한 브라우저를 사용할 때만 해당
지속적으로 필요한 데이터 저장 (자동 로그인 등)
sessionStorage
데이터가 오리진 뿐만 아니라 브라우저 탭에도 종속되기 때문에, 윈도우나 브라우저 탭을 닫을 경우 제거
일시적으로 필요한 데이터 저장 (일회성 로그인 정보, 입력폼 저장 등)
import React, { useState } from "https://cdn.skypack.dev/react@18";
import ReactDOM from "https://cdn.skypack.dev/react-dom@18";
import {
RecoilRoot,
atom,
atomFamily,
useRecoilState
} from "https://cdn.skypack.dev/recoil";
import { recoilPersist } from "https://cdn.skypack.dev/recoil-persist";
const { persistAtom } = recoilPersist();
const pageNo1Atom = atom({
key: "app/pageNo1Atom",
default: 0,
effects_UNSTABLE : [persistAtom],
});
const pageNoAtomFamily = atomFamily({
key: "app/pageNoAtomFamily",
default: (no) => 0
});
function Page1() {
const [no, setNo] = useRecoilState(pageNo1Atom);
return (
<>
<h3>페이지1</h3>
<ul>
<li>페이지 1의 숫자 : {no}</li>
<li>
<button onClick={() => setNo(no + 1)}>증가</button>
</li>
</ul>
</>
);
}
function Page2() {
const [no, setNo] = useRecoilState(pageNoAtomFamily(2));
return (
<>
<h3>페이지2</h3>
<ul>
<li>페이지 2의 숫자 : {no}</li>
<li>
<button onClick={() => setNo(no + 1)}>증가</button>
</li>
</ul>
</>
);
}
function Page3() {
const [no, setNo] = useRecoilState(pageNoAtomFamily(2));
return (
<>
<h3>페이지3</h3>
<ul>
<li>페이지 3의 숫자 : {no}</li>
<li>
<button onClick={() => setNo(no + 1)}>증가</button>
</li>
</ul>
</>
);
}
function Page4() {
const [no, setNo] = useRecoilState(pageNoAtomFamily(1));
return (
<>
<h3>페이지4(페이지1의 데이터를 공유 받음)</h3>
<ul>
<li>페이지 4의 숫자 : {no}</li>
<li>
<button onClick={() => setNo(no + 1)}>증가</button>
</li>
</ul>
</>
);
}
const App = () => {
const [pageNo, setPageNo] = useState(1);
const switchPage = () => {
setPageNo(pageNo + 1 <= 4 ? pageNo + 1 : 1);
};
const pageName = "page" + pageNo;
return (
<>
<button onClick={switchPage}>스위치</button>
{pageName == "page1" && <Page1 />}
{pageName == "page2" && <Page2 />}
{pageName == "page3" && <Page3 />}
{pageName == "page4" && <Page4 />}
</>
);
};
function Root() {
return (
<RecoilRoot>
<App />
</RecoilRoot>
);
}