[React]Recoil 기초

Inung_92·2023년 10월 12일
1

React

목록 보기
9/15
post-thumbnail

포스팅 목적

📖React의 localState의 한계를 보완하여 전역적 상태관리를 하기 위하여 Recoil의 기본적인 개념과 기초 사용방법을 알아보자.

사용 목적

📖React 자체 내장된 상태 관리 기능의 한계를 극복하여 API와 상태의 의미와 동작을 가능한 React 답게 유지하기 위하여 사용한다.

React의 한계?

  • React의 상태는 공통된 상위 요소까지 끌어올려야만 공유될 수 있다.
  • 위 과정에서 불필요한 트리가 렌더링되는 현상을 야기한다.
  • Context는 단일 값 저장만 가능하고 자체 소비자를 가지는 여러 값의 집합을 담을 수 없다.
    • React Context는 단일 값만 저장 가능하므로 그룹화가 필요하거나 다양한 ‘Context’에 나누어 저장해야하는 불편함이 발생함.
  • 위에서 언급한 요인들로 인해 최상단(state 존재지점)부터 최말단(사용되는 지점)까지 코드 분할이 어렵다.

그럼 Recoil은?

  • 직교(orthogonal)한다. 즉, 한 개념이나 시스템의 변경이 다른 개념이나 시스템에 영향을 주지 않는다.
  • 본질적 방향 그래프를 정의하여 React 트리에 붙인다.
    • 본질적 방향 그래프 : 상태의 의존성을 표현하는 방식으로 방향성을 가지며 상태 간의 의존성을 명확히 정의
    • React 트리 : 컴포넌트 트리로 컴포넌트들의 계층 구조
    • 상태의 의존성을 나타내는 방향 그래프를 구성하여 React 컴포넌트 트리에 연결한다는 의미
    • 이로 인해 React 컴포넌트들이 Recoil 상태에 의존하는 관계를 명확히 알고 상태 변경에 따라 컴포넌트의 업데이트가 효율적으로 이루어짐
  • 상태 변화는 뿌리(atoms) → 순수 함수(selectors) → 컴포넌트 순으로 흐른다.
  • 주요 특징
    • 동시성 모드 등 React의 새로운 기능과 지원
    • 상태 정의는 점진적이고 분산되어 코드 분할이 용이
    • 상태를 사용하는 컴포넌트를 수정하지 않고 파생된 데이터로 대체 가능
    • 파생된 데이터를 사용하는 컴포넌트를 수정하지 않고 동기식과 비동기식 간 이동 가능
    • 전체 애플리케이션 상태를 하위 호환되는 방식으로 유지하기 용이

즉, Recoil은 React 상태 관리의 한계를 극복하여 불필요한 렌더링 현상을 축소하고, 공유 상태를 내부 상태처럼 간단한 인터페이스로 사용할 수 있도록 지원한다.

또한, 코드 분할의 용이성을 통해 유지보수 및 재사용에 도움을 준다.

설치 방법

// 안전화된 최신 버전
npm install recoil

// CDN
<script src="https://cdn.jsdelivr.net/npm/recoil@0.0.11/umd/recoil.production.js"></script>

// ESLint(eslint-plugin-hooks 사용의 경우)
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": [
      "warn",
      {
        "additionalHooks": "useRecoilCallback"
      }
    ]
  }
}

기초

주요 개념

Atoms

📖상태의 단위로 업데이트와 구독이 가능하다. atom이 업데이트되면 구독된 컴포넌트는 새로운 값을 반영하여 리-렌더링된다. 동일한 atom이 여러 컴포넌트들에서 사용이 되는 경우 해당 컴포넌트들은 상태를 공유한다.

  • 생성
    // atom 생성
    const testState = atom({
    	key: 'testState',  // 고유한 키값으로 전역적으로 고유해야한다. (2개 이상의 atom이 같은 키값을 갖는 경우 오류 발생)
    	default: '', // state의 기본값
    });
  • 호출
    // atom 호출
    export const TestButton = () => {
    	// React의 컴포넌트 상태 : const [testState, setTestState] = useState('');
    	const [testState, setTestState] = useRecoilState(testState); // useState()와 비슷하게 사용되지만 컴포넌트 간 상태 공유가 가능하다.
    	
    	return (
    		<button onClick={() => setTestState()}>Click</button>
    	);
    };

Selectors

📖atoms나 다른 selectors를 입력으로 받아들이는 순수 함수. 상위의 atoms 또는 selectors가 업데이트되면 하위의 selectors 함수도 다시 실행되는 특성이 있다.

atoms와 마찬가지로 컴포넌트들이 구독할 수 있으며, selectors의 변경에 따라 구독한 컴포넌트들이 리-렌더링되는 것도 동일하다.

selectors의 주요 특징은 다음과 같다.

  • 상태를 기반으로 하는 파생 데이터를 계산하는 데 사용
  • 최소한의 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 계산함으로 쓸모없는 상태의 보존을 방지
  • 자신을 의존하는 컴포넌트 또는 자신이 의존하는 상태를 추적하여 함수적인 접근방식을 매우 효율적으로 개선

사용은 다음과 같다.

  • 생성
    // selector 생성
    const testSelectorState = selector({
    	key: 'testSelectorState',
    	get: ({get}) => {
    		const testState = get(testState); // testState를 참조. 참조대상이 변하면 해당 함수 다시 실행
    		const unit = 'test';
    
    		return testState + unit;
    	},
    });
    위 코드에서 get은 계산될 함수다. 계산될 함수라는 말은 get에 전달될 인자를 통해 접근해야 할 대상이 정해지는 것이다. get의 인자를 통해 atoms와 다른 selectors에 접근 할 수 있다. 이 때 자동으로 종속 관계가 생성되어 참조했던 atoms나 selectors가 업데이트 되면 해당 함수도 다시 실행된다.
  • 호출
    // selector 호출
    export const TestButton = () => {
    	const [testState, setTestState] = useRecoilState(testState);
    	const testSelectorState = useRecoilValue(testSelectorState); // selector
    
    	return (
    		...생략
    	);
    };
    selector는 useRecoilValue()를 통해 호출한다. 이유는 writable하지 않기 때문이다. useRecoilState()는 atoms에서 확인할 수 있듯이 setter를 반환한다. 하지만 selector는 명시적으로 set 함수를 설정하지 않으면 수정할 수 없는 상태가 된다.

마무리

Recoil을 아주 기초만 다루어 보았지만 굉장히 유용하다는 생각이 들었던 동시에 프로젝트의 규모가 커지면 관리하기가 쉽지 않겠다는 생각도 같이 들었다. 그래서 개념부터 차근차근 들여다 보면서 천천히 익히려고 마음을 먹었던 것 같다.

사용해야하는 부분에 대한 파악을 명확히해서 프로젝트 내에서 공유 상태 관리로써 효율적인 사용이 가능토록 연습이 필요하다.

그럼 이만.👊🏽

profile
서핑하는 개발자🏄🏽

0개의 댓글