본문 바로가기
Front-end/React

Recoil 사용 연습하기 - 1

by 질서정연_ 2023. 3. 21.

 

Recoil 개념 

recoiil 에서 하나의 전역 상태는 Atom 이라고 부른다.

Atom 은 어느 하나의 컴포넌트에 묶여있지 않고, 모든 컴포넌트에서 접근 가능한 하나의 그래프이다. 

Atom 상태를 구독하여 업데이트되는 Selector 혹은 Atom 을 자식으로 점점 붙여나갈 수 있다.

Recoild 도 Redux처럼 단방향 데이터 흐름을 가진다.

Recoil 을 사용하면 atoms(공유상태)에서 selectors(순수함수) 를 거쳐 React 컴포넌트로 내려가는 

data-flow graph 를 만들 수 있다. 

Atoms은 컴포넌트가 구독할 수 있는 상태의 단위이다.

Selectors는 atoms 상태값을 동기 또는 비동기 방식을 통해 변환한다. 

 

Atoms

Atoms는 상태의 단위이며, 업데이트와 구독이 가능하다.

atom 이 업데이트 되면 각각의 구독된 컴포넌트는 새로운 값을 반영하여 다시 렌더링된다.

atoms는 런타임에서 생성될 수도 있다. 

Atoms는 React 의 로컬 컴포넌트의 상태 대신 사용할 수 있다. 

동일한 atom 이 여러 컴포넌트에서 사용되는 경우 모든 컴포넌트는 상태를 공유한다. 

 

 Atoms는 atom 함수를 사용해 생성한다. 

const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});

Atoms는 디버깅, 지속성 및 모든 atoms의 map을 볼 수 있는 특정 고급 API에 사용되는 고유한 키가 필요하다.

두개의 atom 이 같은 키를 갖는 것은 오류이기 때문에 키값은 전역적으로 고유하도록 해야한다.

React 컴포넌트의 상태처럼 기본값도 가진다. 

 

정리

atoms는 고유한 키가 필요하다. 키값은 전역적으로 고유해야한다.

기본값도 가진다. 

 

컴포넌트에서 atom 을 읽고 쓰려면 useRecoilState 라는 훅을 사용한다. 

React 의 useState와 비슷하지만 상태가 컴포넌트간에 공유될 수 있다는 차이가 있다. 

 

Selectors

Selector는 atoms나 다른 selectors를 입력으로 받아들이는 순수함수(pure function)이다.

상위의 atoms또는 selectors가 업데이트되면 하위의 selector 함수도 다시 실행된다. 

컴포넌트들은 selectors를 atoms처럼 구독할 수 있으며 

selectors가 변경되면 컴포넌트들도 다시 렌더링된다. 

 

Selectors는 상태를 기반으로 하는 파생 데이터를 계산하는 데 사용된다. 

최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 

효율적으로 계산함으로써 쓸모없는 상태의 보존을 방지한다. 

 

Selectors는 어떤 컴포넌트가 자신을 필요로하는지, 또 자신은 어떤 상태에 의존하는지를 추적하기때문에

이러한 함수적인 접근 방식을 매우 효육적으로 만든다. 

 

Selectors는 selector 함수를 사용해 정의한다. 

 

const fontSizeLabelState = selector({
  key: 'fontSizeLabelState',
  get: ({get}) => {
    const fontSize = get(fontSizeState);
    const unit = 'px';

    return `${fontSize}${unit}`;
  },
});

get 속성은 계산될 함수다.

전달되는 get 인자를 통해 atoms 와 다른 selectors에 접근할 수 있다. 

다른 atoms나 selectors에 접근하면 자동으로 종속관계가 생성되므로,

참조했던 다른 atoms나 selectors가 업데이트되면 이 함수도 다시 실행된다. 

 

이 fontSizeLabelState 예시에서 selector는 fontSizeState라는 하나의 atom에 의존성을 갖는다. 

개념적으로 fontSizeLabelState selector는 fontSizeState를 입력으로 사용하고 

형식화된 글꼴 크기 레이블을 출력으로 반환하는 순수 함수처럼 동작한다. 

 

Selectors는 useRecoilValue()를 사용해 읽을 수 있다. useRecoilValue() 는 하나의 atom 이나 selector를 인자로 받아 대응하는 값을 반환한다. 

 

Selector는 파생된 상태(derived state)의 일부를 나타낸다. 파생된 상태는 상태의 변화다. 파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다. 

그럼 이제 실습 해 보자 ! 

recoil 상태를 사용하는 컴포넌트는 부모트리 어딘가에 나타나는 RecoilRoot가 필요하다.루트 컴포넌트가 RecoilRoot 를 넣기 가장 좋은 장소다.

 

1. npm install recoil 로 Recoil 패키지 설치하기

npm install recoil

 

2. recoil 상태를 사용하는 컴포넌트는 부모트리 어딘가에 나타나는 RecoilRoot가 필요하다.

부모컴포넌트에 RecoilRoot 넣기 

import React from 'react';
import {
  RecoilRoot,
  atom,
  selector,
  useRecoilState,
  useRecoilValue,
} from 'recoil';

function App() {
  return (
    <RecoilRoot>
      <CharacterCounter />
    </RecoilRoot>
  );
}

 

3. atom 생성하기

const textState = atom({
	key: 'textState',
	default: '',
})

 

const [text,setText] = useCoilState(textState)

 

 

4. atom 연산을 위한 selector를 생성하고 selector에 atom 넣기 

selector 도 atom 처럼 고유 key 와 value 가 필요하다. 

const charCountState = selector({
	key: 'charCountState',
    get: ((get))=>{
    	const text = get(textState);
        
        return text.length
    }
});

typescript create-react-app project Installation 

npx create-react-app my-app --template typescript

 

간단한 예제 코드 

import React from 'react';
import {
  RecoilRoot,
  atom,
  selector, 
  useRecoilState,
  useRecoilValue,
} from 'recoil';

function App() {

  const textState = atom({
    key:'textState', // 고유한 값
    default:'', // 초기값
  });

  

  function TextInput(){
    const [text, setText] = useRecoilState(textState);

    const onChange = (event:any) => {
      setText(event.target.value);
    }

    return (
      <div>
        <input type="text" value={text} onChange={onChange}/>
        <br />
        Echo: {text}
      </div>
    )
  };

  const charCountState = selector({
    key:'charCountState',
    get: ({get})=>{
      const text = get(textState);

      return text.length;
    },
  })

  function CharacterCount(){
    const count = useRecoilValue(charCountState);

    return <>Character Count: {count}</>;
  }

  function CharacterCounter(){
    return (
      <div>
        <TextInput />
        <CharacterCount />
      </div>
    )
  }

  return (
    <RecoilRoot>
      <CharacterCounter />
    </RecoilRoot>
  );
}

export default App;

 

 

참조 

https://recoiljs.org/ko/docs/introduction/getting-started

 

Recoil 시작하기 | Recoil

React 애플리케이션 생성하기

recoiljs.org

 

댓글