import * as ReactDOMClient from "react-dom/client";
import { RecoilRoot } from "recoil";
import App from "./App";
const rootElement = document.getElementById("root");
const root = ReactDOMClient.createRoot(rootElement);
root.render(
<RecoilRoot>
<App />
</RecoilRoot>
)
;
import { atom } from "recoil"
export const user = atom({
key: "user",
default: {
id: "Admin",
pwd: "Admin",
},
});
export const counting = atom({
key: "counting",
default: 0,
});
import { useRecoilState } from "recoil";
import { counting } from "./store";
export function Example() {
const [count, setCount] = useRecoilState(counting);
const handleIncrease = () => {
setCount((prev) => prev + 1);
}
return (
<div>
<span>{count}</span>
<button onClick={handleIncrease}>increase</button>
</div>
);
}
//atom.ts
import { atom } from "recoil";
export interface IUser {
id: string;
pwd: string;
name: string;
}
export const user = atom<IUser>({
key: "user",
default: {
id: "admin",
pwd: "admin",
name: "관리자"
}
});
// App.tsx
import { useRecoilState } from "recoil";
import { IUser, user } from "./atom";
export default function App() {
const [LoginUser, setLoginUser] = useRecoilState<IUser>(user);
return (
<div>
<p>userName: {LoginUser.name}</p>
<p>userId: {LoginUser.id}</p>
<p>userPwd: {LoginUser.pwd}</p>
</div>
);
}
selector을 활용해 비동기 통신을 했을 때 체감되는 강력한 기능은 캐싱 이다. selector을 활용해 비동기 통신을 해온다면, 내부적으로 알아서 값을 캐싱 해주기 때문에 이미 한번 비동기 통신을 하여 값이 캐싱되어 있다면 매번 같은 비동기 통신을 하지 않고 캐싱 된 값을 추적해 사용한다.
// atom.ts
import { atom, selector } from "recoil";
export type status = "DONE" | "DOING";
interface toDo {
status: status;
contents: string;
}
export const selectStatus = atom<status>({
key: "nowStatus",
default: "DOING"
});
export const toDos = atom<toDo[]>({
key: "toDos",
default: [
{ status: "DOING", contents: "default 1" },
{ status: "DONE", contents: "default 2" },
{ status: "DONE", contents: "default 3" },
{ status: "DOING", contents: "default 4" },
{ status: "DOING", contents: "default 5" }
]
});
export const selectToDo = selector<toDo[]>({
key: "selectToDos",
get: ({ get }) => {
const originalToDos = get(toDos);
const nowStatus = get(selectStatus);
return originalToDos.filter((toDo) => toDo.status === nowStatus);
}
});
// App.tsx
import React from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { selectStatus, selectToDo, user } from "./atom";
export default function App() {
const [status, setStatus] = useRecoilState(selectStatus);
const selectToDos = useRecoilValue(selectToDo);
const handleStatus = (event: React.ChangeEvent<HTMLSelectElement>) => {
setStatus(event.currentTarget.value as any);
};
return (
<>
<div>
<select value={status} onChange={handleStatus}>
<option value="DOING">DOING</option>
<option value="DONE">DONE</option>
</select>
<ul>
{selectToDos.map((toDo, index) => {
return (
<li key={index}>
<span>status: {toDo.status}</span>
<br />
<span>content: {toDo.contents}</span>
</li>
);
})}
</ul>
</div>
</>
);
}
// atom.ts
export const selectToDo = selector<toDo[]>({
key: "selectToDos",
get: ({ get }) => {
const originalToDos = get(toDos);
const nowStatus = get(selectStatus);
return originalToDos.filter((toDo) => toDo.status === nowStatus);
},
set: ({ set }, newToDo) => {
set(toDos, newToDo);
}
}
);
import React, { useState } from "react";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import { selectStatus, selectToDo, toDo, toDos } from "./atom";
export default function App() {
const [status, setStatus] = useRecoilState(selectStatus);
const selectToDos = useRecoilValue(selectToDo);
const toDoAtom = useRecoilValue(toDos);
// 아래가 selector 의 set 을 위해 추가된 코드
const [contents, setContents] = useState("");
const setNewToDos = useSetRecoilState(selectToDo);
const handleStatus = (event: React.ChangeEvent<HTMLSelectElement>) => {
setStatus(event.currentTarget.value as any);
};
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setContents(event.currentTarget.value);
};
const handleSubmit = (event: React.ChangeEvent<HTMLFormElement>) => {
event.preventDefault();
if (contents === "") {
return;
} else {
const newToDoList: toDo[] = [
...toDoAtom,
{
contents,
status: "DOING"
}
];
setNewToDos(newToDoList);
setContents("");
}
};
return (
<>
<form onSubmit={handleSubmit}>
<input value={contents} onChange={handleInputChange} />
<button>Submit</button>
</form>
<br />
<div>
<select value={status} onChange={handleStatus}>
<option value="DOING">DOING</option>
<option value="DONE">DONE</option>
</select>
<ul>
{selectToDos.map((toDo, index) => {
return (
<li key={index}>
<span>status: {toDo.status}</span>
<br />
<span>content: {toDo.contents}</span>
</li>
);
})}
</ul>
</div>
</>
);
}
export const selectId = atom({
key: "selectId",
default: 1
});
export const selectingUser = selector({
key: "selectingUser",
get: async ({ get }) => {
const id = get(selectId);
const user = await fetch(
`https://jsonplaceholder.typicode.com/users/${id}`
).then((res) => res.json());
return user;
},
set: ({ set }, newValue) => {
set(nowUser as any, newValue);
}
});
export const selectUser = selectorFamily({
key: "selectOne",
get: (id: number) => async () => {
const user = fetch(
`https://jsonplaceholder.typicode.com/users/${id}`
).then((res) => res.json());
return user;
}
});
// 컴포넌트에서 사용 시
const user = useRecoilValue<IUser>(selectUser(id));