ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React 상태 관리 : Recoil 로 해보자!
    Front-end/React 2021. 12. 4. 18:42
    반응형

     

    일반적으로 많은 회사에서 redux, mobx를 사용하는 얘기는 들었다.

    나 또한 Redux, mobx는 경험이 있지만 Recoil은 얘기만 들어봤지 사용해보진 않았는데 그래서 documentation을 따라해보면서 알아가보려고 한다.

     

    나는 머리가 좋지 않다.

    그래서 하나하나 잘 따져가면서 공부를 해야한다.

    redux를 익힐 때 고생했던 경험을 살려... 이번에는 redux를 익혔을 때의 순서를 지켜가면서 공부를 해봐야겠다


    About Recoil

     

    우선 각 상태관리 라이브러리들의 architecture 에 대해서 머리에 그림을 그려야 한다.

    Redux의 경우, Flux architecture를 기반으로 했고, mobX의 경우 Proxy, Context API는 context를 기반으로 했다.

    그렇다면 Recoil은? 바로 Atomic 이다.

     

    Recoil은 React를 만든 Facebook에서 만들었다.

    그러므로 더 잘 어울리게 만들었을 것이라는 믿음이 생기는 부분이었다.

     

    Recoil은 React의 내부 상태만을 이용하게 된다.

    아주 작은 atom 단위로 관리되며, selector라는 순수함수를 제공한다.

    상태가 변경되면 atom을 참조하는 component만 re-rendering 되기 때문에 re-render의 최소화를 기대할 수 있다.


    Let's use Recoil

    한글화로 문서화가 잘 되어 있어서 Recoil 시작하기를 통해서 도전해보자!

    우선 얼핏봐도 Redux에 비해 런닝커브가 비교적 낮다는 것을 알 수 있다.

     

    cra를 통해서 리액트를 설치하고,

    yarn create react-app recoil-tutorial

     recoil도 설치를 하자.

    yarn add recoil

     

    그리고 RecoilRoot를 만들어야 한다.

    index.js에서 전체를 다 감싸주도록 하자.

    // src > index.js
    
    import React from "react";
    import ReactDOM from "react-dom";
    import "./index.css";
    import App from "./App";
    import { RecoilRoot } from "recoil";
    
    ReactDOM.render(
      <React.StrictMode>
        <RecoilRoot>
          <App />
        </RecoilRoot>
      </React.StrictMode>,
      document.getElementById("root")
    );

     

    components라는 폴더에 CharactorCounter.jsx, TextInput.jsx, CharacterCount.jsx를 만들어보자.

    // src > components > TextInput.jsx
    
    import React from "react";
    
    const TextInput = () => {
      return (
        <div>
    	TextInput
        </div>
      );
    };
    
    export default TextInput;
    // src > components > CharacterCounter.jsx
    
    import React from "react";
    
    const CharacterCounter = () => {
      return <div>character count : 0</div>;
    };
    
    export default CharacterCounter;
    // src > components > CharactorCounter.jsx
    
    import React from "react";
    import CharacterCount from "./CharacterCount";
    import TextInput from "./TextInput";
    
    const ChrarctorCounter = () => {
      return (
        <div>
          <TextInput />
          <CharacterCount />
        </div>
      );
    };
    
    export default ChrarctorCounter;

    우선은 이렇게 만들어서 App.js에서 불러오자.

     

    그리고 recoil 폴더를 만들어서 atom.js를 먼저 만들것이다.

    // src > recoil > atom.js
    
    import { atom } from "recoil";
    
    export const textState = atom({
      key: "text",
      default: "",
    });
    
    // key : Unique ID
    // default: initial value

    atom은 이런 식으로 사용 할 수 있는데, key 값은 unique 해야하고, default 값은 initial value라고 생각하면 된다.

     

    recoil의 atom은 state의 일부를 나타내는데 어떤 컴포넌트에서나 읽고 쓸 수 있다.

    atom의 값을 읽게 되는 컴포넌트들은 암묵적으로 atom을 subscribe 한다.

    그래서 atom의 업데이트는 subscribe 하고 있는 모든 컴포넌트를 re-rendering하게 만든다.

     

    Atom이 만들어졌다면 Selector도 만들어보자.

    selector는 atom state에 의존하는 동적인 데이터를 생성한다.

    atom에 의존하므로 atom의 정보가 바뀌게 되면 selector도 자동으로 re-rendering 된다.

    get이라는 함수를 사용하게 되어있는데 이를 통해서 atom의 정보를 가져올 수 있다.

    그리고 set함수를 통해서 atom 정보를 업데이트 하도록 할 수 있다.

    // src > recoil > selector.js
    
    import { selector } from "recoil";
    import { textState } from "../atoms/atom";
    
    export const charCountState = selector({
      key: "charCountState", 
      get: ({ get }) => {
        const text = get(textState);
    
        return text.length;
      },
    });

     

    그렇다면 이를 사용해보자.


     [ 그 전에 잠깐!!! recoil에서 사용되어지는 hook을 짧게 살펴보자 ]

     

    1. useRecoilState

    기본 값 대신 Recoil state를 인수로 받는다는 점만 제외하면 useState hook과 비슷하다고 볼 수 있다.
    이는 컴포넌트가 상태를 읽고 쓰려고 할 때 사용이 권장 되어진다.

    example) const [text, setText] = useRecoilState(textState)

    2. useSetRecoilState

    Recoil state value(subscribe하는 value)를 업데이트하기 위한 setter 함수를 반환한다.

    이 hook은 컴포넌트가 상태를 읽지 않고 쓰기만 하려고 할 때 권장되어진다.

    example)
    function Form() {
      const setNamesState = useSetRecoilState(namesState); 
      return <FormContent setNamesState={setNamesState} />;
    }

    위 예시의 컴포넌트는 마운트 될 때 한번만 랜더링 되어질 것이다.

     

    3. useRecoilValue

    주어진 Recoil state value를 반환한다.

    이는 읽기 전용 상태, 쓰기 가능 상태에서 모두 동작하므로 컴포넌트가 상태를 읽을 수만 있게 하고 싶을 때 사용 권장이 되어지는 hook이다.

    값의 업데이트를 할 필요 없는 경우 사용 할 수 있을 것이다.

    또한 React에서 사용하면 상태가 업데이트 될 때 re-rendering 되도록 컴포넌트를 subscribe 하고, state가 error를 가지고 있거나, 보류 중인 비동기 resolution이 있다면 던져줄 수 있다.

     

    4. useResetRecoilState

    이는 비동기 selector의 값을 읽기 위해 사용 된다.

    상태를 기본값으로 reset 할 수 있게 해준다.

    // example)
    import {todoListState} from "../atoms/todoListState";
    
    const TodoResetButton = () => {
      const resetList = useResetRecoilState(todoListState);
      return <button onClick={resetList}>Reset</button>;
    };

    다시 돌아와서, 앞서 만든 TextInput.jsx에 useRecoilState를 사용해볼 수 있다.

    // src > components > TextInput.jsx
    
    import React from "react";
    import { useRecoilState } from "recoil";
    import { textState } from "../recoil/atoms/atom";
    
    const TextInput = () => {
      const [stateText, setStateText] = useRecoilState(textState);
    
      const changeHandler = (e) => {
        setStateText(e.target.value);
      };
    
      return (
        <div>
          <input type="text" value={stateText} onChange={changeHandler} />
          <br />
          Echo: {stateText}
        </div>
      );
    };
    
    export default TextInput;

    앞서 설명 했던 Recoil의 hook 중 useRecoilState를 사용해서  만들었다.

     

    이어서 CharacterCount.jsx를 만들어보자

    import React from "react";
    import { useRecoilValue } from "recoil";
    import { charCountState } from "../recoil/selectors/selector";
    
    const CharacterCounter = () => {
      const count = useRecoilValue(charCountState);
    
      return <div>character count : {count}</div>;
    };
    
    export default CharacterCounter;

    이는 useRecoilValue를 사용하여서 만들 수 있다.

    그러면 아래처럼 사용이 가능하다.

    이것이 Recoil의 기초적인 사용 방법이다.

    반응형
Designed by Tistory.