Previewlocked to source

1인 프로젝트 개발을 하던 중 전역 상태 관리가 필요해진 시점에서 누군가 저에게 말했습니다. useRecoil을 쓴다면 편하게 전역관리를 할 수 있으니 시도해보지 않겠냐고

'상태 관리'에 대한 정의

  • 애플리케이션의 동작 방식을 설명하는 모든 데이터

  • David Khourshid - 상태관리는 시간이 지남에 따라 상태가 변경되는 방식입니다.

  • 상태 '관리'가 되려면 기본적으로 3가지 기능을 해야 합니다.

    • 최초 값(initial value)를 저장
    • 현재 값(current value)를 읽기
    • 값을 업데이트

그렇다면 Recoil은 왜필요한가?

  • React의 내장 상태 관리 '기능'의 한계점 극복
  • 그 중에 최대한 React스러운 API 유지
    • 어떠한 특별한 runningCommand없이 간단하게 접근이 가능합니다.
  • 사용하기 위한 부속 라이브러리 최소화

React 상태 관리 로직의 한계점

  • 컴포넌트의 상태는 공통되는 부모 컴포넌트까지 올라가야하는데 심할 경우 애플리케이션 상단까지 올라가야하는 문제가 발생할 수 있음
  • Context API는 확정되지 않은 수의 값을 저장하는데 적합하지 않으며 최적화 관점의 한계점이 명확함
    • Context API는 각 상태마다 Context Provider가 필요한데 상태가 1000개라면 1000개의 Provider를 선언해야 합니다.
    • 상태가 변경될 때마다 캐싱 없이 매번 re-rendering 합니다.
  • Redux는 별도의 라이브러리가 필요하고 초기 구축, 유지 보수 과정에서 boilerplate 코드를 많이 작성해야 합니다.
    • React concurrent renderer를 지원하지 않습니다.

Recoil의 접근 방법

  • Recoil은 React Tree에 직교되는 형태로 존재하는 방향 그래프(Directed Graph)로 구성되어 있습니다.
  • 상태의 변경은 이 그래프를 따라 React Component로 흘러 들어갑니다.
    • 다양한 장점들이 있지만 가장 큰 장점으로 Component쪽의 로직을 건드리지 않고 상태 데이터를 단독으로 변경할 수 있다는 큰 장점이 있습니다.

Recoil의 철학

  • boilerplate가 적은 API면서 React의 로컬 상태(useState, useReducer) 유사한 간단한 인터페이스
  • Concurrent Mode와 호환
  • 코드 상호간의 낮은 결합도를 통해 Code splitting 용이성 확보
  • 파생 데이터를 사용함으로써 데이터를 사용하는 컴포넌트에서 임의로 데이터를 바꾸는 로직을 가져가지 않아도 됩니다.
    • 가져와서 useEffect로 바꿔주기를 하지 않고 로직 자체를 Recoil atom에 귀속시킬 수 있습니다.
// 기존 useEffect로 업데이트 해줘야하는 점
useEffect(() => {
  (async () => {
      await updateState();
      await updateAnotherState();
  }) ();
}, []);

// 업데이트 필요없이 useState와 유사한 업데이트 방식
const tempFahrenheit = atom({
  key: 'tempFahrenheit',
  default: 32,
});

const tempCelsius = selector({
  key: 'tempCelsius',
  get: ({get}) => ((get(tempFahrenheit) - 32) * 5) / 9,
  set: ({set}, newValue) => set(tempFahrenheit, (newValue * 9) / 5 + 32),
});

function TempCelsius() {
  const [tempF, setTempF] = useRecoilState(tempFahrenheit);
  const [tempC, setTempC] = useRecoilState(tempCelsius);
  

Core Concept

Atom

  • 데이터를 보관하는 기본 단위
  • Redux로 따지자면 store와 유사한 개념으로 상태의 단위를 뜻합니다.
  • atom이 업데이트 된다면 해당 atom을 구독하고 있던 모든 Component의 state가 업데이트 됩니다.
  • 유니크한 id인 key값으로 구분되는 각 atom은 여러 컴포넌트에서 해당 atom을 구독하고 있다면 그 컴포넌트도 똑같은 상태를 유지합니다.

state.js

export const cookieState = atom({
  key: 'cookieState',
  default: []
});

Cookie.js

import React from 'react'
import { cookieState } from '../../state';
import { useRecoilState } from 'recoil';

const Cookie = () => {
	const [cookies, setCookies] = useRecoilState(cookieState);
  
  return(
    <div>
        {cookie.map(cookie => (
          <Card
            cookies={cookie}
            key={cookie.id}
            idx={cookie.id}
           />
       ))}
      </div>
  );
}
export default Cookie;

Selector

  • selector는 atom을 전/후 처리하여 새로운 값을 리턴하거나 기존 atom의 값을 수정할 때 사용합니다.
    • atom의 값이 최신화 되면 selector의 값 또한 최신화되어 편하게 사용할 수 있습니다.
  • selector를 사용하면 atom을 직접 변경하지 않기 때문에 불변성 유지가 가능합니다.
  • selector는 순수함수로 같은 입력이 들어오면 해당 입력에 대한 출력은 항상 같은 함수라는 것을 의미합니다.
  • selector는 read-only한 RecoilValueReadOnly 객체로써 return값 만을 가질 수 있고 값을 set 할 수 없는 특징이 있습니다.
export const sampleState = atom({
  key: "sampleState",
  default: 0,
});

export const sampleSelector = selector({
  key: "sampleSelector",
  get: ({ get }) => get(sampleState) * 2,
  set: ({ set }, newValue) => set(sampleState, newValue / 2),
});

마치며

useRecoil에 대해서 알아보니 편리한 사용성과 간단한 로직이 마음에 들었습니다. 간결한 코드와 컴포넌트의 로직을 건드리지 않고 상태관리를 할 수 있단 점이 마음에 들었고 아직 기초적인 것만 활용해 잘은 모르지만 이를 활용해 프로젝트를 구현해보려고 합니다.

postsuseRecoil의 개념.md
010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
> 1인 프로젝트 개발을 하던 중 전역 상태 관리가 필요해진 시점에서 누군가 저에게 말했습니다. useRecoil을 쓴다면 편하게 전역관리를 할 수 있으니 시도해보지 않겠냐고
# '상태 관리'에 대한 정의
- 애플리케이션의 동작 방식을 설명하는 모든 데이터
- David Khourshid - 상태관리는 시간이 지남에 따라 상태가 변경되는 방식입니다.
- 상태 '관리'가 되려면 기본적으로 3가지 기능을 해야 합니다.
- 최초 값(initial value)를 저장
- 현재 값(current value)를 읽기
- 값을 업데이트
# 그렇다면 Recoil은 왜필요한가?
- React의 내장 상태 관리 '기능'의 한계점 극복
- 그 중에 최대한 React스러운 API 유지
- 어떠한 특별한 runningCommand없이 간단하게 접근이 가능합니다.
- 사용하기 위한 부속 라이브러리 최소화
# React 상태 관리 로직의 한계점
- 컴포넌트의 상태는 공통되는 부모 컴포넌트까지 올라가야하는데 심할 경우 애플리케이션 상단까지 올라가야하는 문제가 발생할 수 있음
- **Context API**는 확정되지 않은 수의 값을 저장하는데 적합하지 않으며 최적화 관점의 한계점이 명확함
- Context API는 각 상태마다 Context Provider가 필요한데 상태가 1000개라면 1000개의 Provider를 선언해야 합니다.
- 상태가 변경될 때마다 캐싱 없이 매번 re-rendering 합니다.
- **Redux**는 별도의 라이브러리가 필요하고 초기 구축, 유지 보수 과정에서 boilerplate 코드를 많이 작성해야 합니다.
- React concurrent renderer를 지원하지 않습니다.
# Recoil의 접근 방법
- Recoil은 React Tree에 직교되는 형태로 존재하는 방향 그래프(Directed Graph)로 구성되어 있습니다.
- 상태의 변경은 이 그래프를 따라 React Component로 흘러 들어갑니다.
- 다양한 장점들이 있지만 가장 큰 장점으로 Component쪽의 로직을 건드리지 않고 상태 데이터를 단독으로 변경할 수 있다는 큰 장점이 있습니다.
![](https://velog.velcdn.com/images/dbsghdql555/post/414e7038-eb26-42fa-b1ff-e8a65fd0f2bc/image.png)
# Recoil의 철학
- boilerplate가 적은 API면서 React의 로컬 상태(useState, useReducer) 유사한 간단한 인터페이스
- Concurrent Mode와 호환
- 코드 상호간의 낮은 결합도를 통해 Code splitting 용이성 확보
- 파생 데이터를 사용함으로써 데이터를 사용하는 컴포넌트에서 임의로 데이터를 바꾸는 로직을 가져가지 않아도 됩니다.
- 가져와서 useEffect로 바꿔주기를 하지 않고 로직 자체를 Recoil atom에 귀속시킬 수 있습니다.
```javascript
// 기존 useEffect로 업데이트 해줘야하는 점
useEffect(() => {
(async () => {
await updateState();
await updateAnotherState();
}) ();
}, []);
```
```javascript
// 업데이트 필요없이 useState와 유사한 업데이트 방식
const tempFahrenheit = atom({
key: 'tempFahrenheit',
default: 32,
});
const tempCelsius = selector({
key: 'tempCelsius',
get: ({get}) => ((get(tempFahrenheit) - 32) * 5) / 9,
set: ({set}, newValue) => set(tempFahrenheit, (newValue * 9) / 5 + 32),
});
function TempCelsius() {
const [tempF, setTempF] = useRecoilState(tempFahrenheit);
const [tempC, setTempC] = useRecoilState(tempCelsius);
```
# Core Concept
## Atom
- 데이터를 보관하는 기본 단위
- Redux로 따지자면 store와 유사한 개념으로 상태의 단위를 뜻합니다.
- atom이 업데이트 된다면 해당 atom을 구독하고 있던 모든 Component의 state가 업데이트 됩니다.
- 유니크한 id인 key값으로 구분되는 각 atom은 여러 컴포넌트에서 해당 atom을 구독하고 있다면 그 컴포넌트도 똑같은 상태를 유지합니다.
**state.js**
```javascript
export const cookieState = atom({
key: 'cookieState',
default: []
});
```
**Cookie.js**
```javascript
import React from 'react'
import { cookieState } from '../../state';
import { useRecoilState } from 'recoil';
const Cookie = () => {
const [cookies, setCookies] = useRecoilState(cookieState);
return(
<div>
{cookie.map(cookie => (
<Card
cookies={cookie}
key={cookie.id}
idx={cookie.id}
/>
))}
</div>
);
}
export default Cookie;
```
## Selector
- selector는 atom을 전/후 처리하여 새로운 값을 리턴하거나 기존 atom의 값을 수정할 때 사용합니다.
- atom의 값이 최신화 되면 selector의 값 또한 최신화되어 편하게 사용할 수 있습니다.
- selector를 사용하면 atom을 직접 변경하지 않기 때문에 불변성 유지가 가능합니다.
- selector는 **순수함수**로 같은 입력이 들어오면 해당 입력에 대한 출력은 항상 같은 함수라는 것을 의미합니다.
- selector는 read-only한 RecoilValueReadOnly 객체로써 return값 만을 가질 수 있고 값을 set 할 수 없는 특징이 있습니다.
```javascript
export const sampleState = atom({
key: "sampleState",
default: 0,
});
export const sampleSelector = selector({
key: "sampleSelector",
get: ({ get }) => get(sampleState) * 2,
set: ({ set }, newValue) => set(sampleState, newValue / 2),
});
```
# 마치며
useRecoil에 대해서 알아보니 편리한 사용성과 간단한 로직이 마음에 들었습니다. 간결한 코드와 컴포넌트의 로직을 건드리지 않고 상태관리를 할 수 있단 점이 마음에 들었고 아직 기초적인 것만 활용해 잘은 모르지만 이를 활용해 프로젝트를 구현해보려고 합니다.
hov_i [main] ⚡