일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- ios
- craco
- slice
- Flipper
- 배열
- Typescript
- reactnative
- react-native-camera-roll
- 자료구조와알고리즘
- 파스에러
- 타입스크립트
- 크라코
- react-native-vision-camera
- react-native-image-picker
- sort( )
- Android
- react-hook-form
- js
- 자바스크립트
- react-native
- 모던자바스크립트
- 리액트네이티브
- 유니온타입
- 리액트
- 제네릭타입
- 리액트쿼리
- javascript
- React
- 코드숨
- 프로그래머스
Archives
- Today
- Total
KassyLog
리코일 본문
Recoil
A state management library for React.
recoiljs.org
전역 상태를 관리하는 라이브러리이며 전역 store에서 상태들을 관리하며 컴포넌트가 각 상태를 구독하고 있는 형태로 사용한다.
내부적으로 ref를 통해 상태를 전달하여 리렌더링을 방지할 수 있고, atomic concept를 차용하여 리액트 상태에 가깝게 사용할 수 있다는 장점이 있다.
atoms(공유상태)에서 selectors(순수함수)를 거쳐 리액트 컴포넌트로 내려가는 데이터플로우그래프를 만들 수 있다.
atoms: 컴포넌트가 구독할 수 있는 상태의 단위
- 고유한 키, 기본값 필요
- atom을 읽고 쓰려면 useRecoilState라는 훅을 사용
- React의 useState와 비슷하지만 상태가 컴포넌트 간에 공유될 수 있다는 차이가 있다.
selectors: atoms 상태값을 동기 또는 비동기 방식을 통해 변환
- 상위의 selector 가 업데이트되면 하위의 selector 함수도 다시 실행된다.
- 상태를 기반으로 하는 파생 데이터를 계산하는데 사용
- 최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selector에 명시한 함수를 통해 효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지한다.
- useRecoilValue()를 사용해 읽을 수 있다. useRecoilValue()는 하나의 atom이나 selector를 인자로 받아 대응하는 값을 반환
*내가 작성한 예시 코드
import React, { useState } from "react";
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
useSetRecoilState,
} from "recoil";
const todoListState = atom({
key: "todoListState",
default: [],
});
//filter _ selector활용
const todoListFilterState = atom({
key: "todoListFilterState",
default: "Show All",
});
const filteredTodoListState = selector({
key: "filteredToDoListState", //todoListFilterState, todoListState 의존 따라서 이 두개가 변경되면 재실행
get: ({ get }) => {
const filter = get(todoListFilterState);
const list = get(todoListState);
switch (filter) {
case "Show Complted":
return list.filter((item) => item.isComplete);
case "Show Uncompleted":
return list.filter((item) => !item.isComplete);
default:
return list;
}
},
});
function App() {
return (
<RecoilRoot>
<TodoList />
</RecoilRoot>
);
}
function TodoList() {
const todoList = useRecoilValue(filteredTodoListState); //atom을 읽고 쓰기 위한 훅
return (
<div>
<TodoListStats />
<TodoListFilters />
<TodoItemCreator />
{todoList.map((item) => (
<TodoItem key={item.id} item={item} />
))}
</div>
);
}
//view 컴포넌트
function TodoItemCreator() {
const [inputValue, setInputValue] = useState("");
const setTodoList = useSetRecoilState(todoListState); //setter함수
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++;
}
function TodoItem({ item }) {
const [todoList, setTodoList] = useRecoilState(todoListState); //setter힘수를 얻기위해
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)];
}
function removeItemAtIndex(arr, index) {
return [...arr.slice(0, index), ...arr.slice(index + 1)];
}
function TodoListFilters() {
const [filter, setFilter] = useRecoilState(todoListFilterState);
const updateFilter = ({ target: { value } }) => {
setFilter(value);
};
return (
<>
Filter :
<select value={filter} onChange={updateFilter}>
<option value="Show All">All</option>
<option value="Show Completed">Completed</option>
<option value="Show Uncompleted">Uncompleted</option>
</select>
</>
);
}
const todoListStatsState = selector({
key: "todoListStatsState",
get: ({ get }) => {
const todoList = get(todoListState);
const totalNum = todoList.length;
const totalCompletedNum = todoList.filter((item) => item.isComplete).length;
const totalUncompletedNum = totalNum - totalCompletedNum;
const percentCompleted = totalNum === 0 ? 0 : totalCompletedNum / totalNum;
return {
totalNum,
totalCompletedNum,
totalUncompletedNum,
percentCompleted,
};
},
});
function TodoListStats() {
const { totalNum, totalCompletedNum, totalUncompletedNum, percentCompleted } =
useRecoilValue(todoListStatsState);
const formattedPercentCompleted = Math.round(percentCompleted);
return (
<ul>
<li>Total items : {totalNum}</li>
<li>Items completed : {totalCompletedNum}</li>
<li>Items not completed : {totalUncompletedNum}</li>
<li>Percent completed : {formattedPercentCompleted}</li>
</ul>
);
}
export default App;
공부 한 내용을 바탕으로 작성한 글이고 앞으로 더 작성할 예정이다.
'react' 카테고리의 다른 글
react 기본 다시 정리해보기! (1) | 2024.02.28 |
---|---|
리액트 쿼리 (0) | 2023.03.27 |
emotion과 styled-components (0) | 2023.03.26 |
craco란? (0) | 2022.12.16 |
Refresh Token (0) | 2022.12.15 |