Recoil은 원자(atom, 공유상태) 에서 Selector(순수 함수)를 거쳐
React Components로 흐르는 데이터 흐름 그래프를 만들게 해줌.
Atom
은 리액트 컴포넌트가 subscribe 할 수 있는 상태 단위이다.
Selector
은 이 상태를 동기식 or 비동기식으로 변환한다.
Redux의 Provider 역할.
여러개의 RecoilRoot가 공존할 수 있고, atom state의 독립적인 공급자를 나타낼 수 있음.
컴포넌트 - recoil 연동시 해당 컴포넌트와 가장 가까이 있는 RecoilRoot를 사용함.
import {RecoilRoot} from 'recoil';
function AppRoot() {
return (
<RecoilRoot>
<ComponentThatUsesRecoil />
</RecoilRoot>
);
}
import { atom } from 'recoil';
const todoListState = atom({
key: 'todoListState',
default: [],
});
const 상태 = atom({ })
의 형태로 선언함.
key
와 기본값인 default
를 설정하면 됨.const [todoList, setTodoList] = useRecoilState(todoListState);
useRecoilState()
는 useState처럼 배열을 반환한다.
인자로는 atom의 key를 적어준다.
구조분해 할당으로 1) state, 2) setState 를 선언해준다.
setState
의 경우에는 setTodoList(todo)
와 같이 값을 넣어주면 된다.
(useState 쓰듯이)
todoList
와 setTodoList
는 아래와 같이 각각 선언해줄 수 있다.
const todoList = useRecoilValue(todoListState);
const setTodoList = useSetRecoilState(todoListState);
Todo List 예제 (cr: https://recoiljs.org/docs/basic-tutorial/atoms)
function TodoList() {
const todoList = useRecoilValue(todoListState);
return (
<>
{/* <TodoListStats /> */}
{/* <TodoListFilters /> */}
<TodoItemCreator />
{todoList.map((todoItem) => (
<TodoItem key={todoItem.id} item={todoItem} />
))}
</>
);
}
function TodoItemCreator() {
const [inputValue, setInputValue] = useState('');
const setTodoList = useSetRecoilState(todoListState);
const addItem = () => {
setTodoList((oldTodoList) => [
...oldTodoList,
{
id: getId(),
text: inputValue,
isComplete: false,
},
]);
setInputValue('');
};
const onChange = ({target: {value}}) => {
setInputValue(value);
};
return (
<div>
<input type="text" value={inputValue} onChange={onChange} />
<button onClick={addItem}>Add</button>
</div>
);
}
// 고유한 Id 생성을 위한 유틸리티
let id = 0;
function getId() {
return id++;
}
item
이라는 props로 전달받음function TodoItem({item}) {
const [todoList, setTodoList] = useRecoilState(todoListState);
// 🔺 todoList를 가져오고, setTodoList도 선언함
const index = todoList.findIndex(listItem => listItem === item);
// 인덱스를 찾아옴
const editItemText = ({target: {value}}) => {
const newList = replaceItemAtIndex(todoList, index, {
...item,
text: value,
});
setTodoList(newList);
};
const toggleItemCompletion = () => {
const newList = replaceItemAtIndex(todoList, index, {
...item,
isComplete: !item.isComplete,
});
setTodoList(newList);
};
const deleteItem = () => {
const newList = removeItemAtIndex(todoList, index);
setTodoList(newList);
};
return (
<div>
<input type="text" value={item.text} onChange={editItemText} />
<input
type="checkbox"
checked={item.isComplete}
onChange={toggleItemCompletion}
/>
<button onClick={deleteItem}>X</button>
</div>
);
}
function replaceItemAtIndex(arr, index, newValue) {
return [...arr.slice(0, index), newValue, ...arr.slice(index + 1)];
}
// ex> i번째 아이템을 수정하려면?
// [1,2,3,4,5].slice(0, i)
) , newValue , ...[1,2,3,4,5].slice(i+1)]
function removeItemAtIndex(arr, index) {
return [...arr.slice(0, index), ...arr.slice(index + 1)];
}
// ex> i번째 아이템을 제거하려면?
// [1,2,3,4,5].slice(0, i), ... [1,2,3,4,5].slice(0, i+1)
![](https://velog.velcdn.com/images/thisisyjin/post/83f17608-20f9-4047-9794-5b029312d904/image.png