Recoil이란?

React.js를 만든 Facebook에서 만든 전역상태관리 라이브러리. 이 이상의 설명은 필요없을 듯 하다.

 

전역 상태란?

컴포넌트에서 쓰이는 상태값(state)가 아닌, 이곳저것에서 전역적으로 쓰이는 상태(state)를 말한다.

 

전역 상태를 사용하는 이유

굳이 안 써도 되긴 한다. 하지만 그렇게 된다면 서로 다른 컴포넌트끼리 특정한 값(= 상태 = state)를 공유하려면 공통된 상위 컴포넌트로부터 prop을 계속 전달하는 방법을 써야 하는데,

 

  • 중간에 거치는 컴포넌트들마다 하나하나 prop을 전달하게끔 코드 작성하는거 귀찮음
  • 중간에 거치는 컴포넌트들은 전달받은 prop을 하위 컴포넌트로 전달만 하고 사용은 안 할 수도. 즉 비효율적
  • 중간에 거치는 컴포넌트들이 많아지면 나중엔 prop을 추적하기가 힘들어짐

 

이런 문제들이 있다. 이 때 전역적으로 쓰는 상태를 만든다면, 어느 컴포넌트에서나 전역 상태에 접근가능하므로 위에서 말한 불편들이 해소될 수 있다!

 

그럼 수많은 전역관리 툴 중 Recoil을 사용하는 이유?

일단 따지고보면 context API는 전역상태관리를 해주는 기능이라기보다는 단순히 전역적으로 상태를 공유하게끔 해주는 기능이라고 보는게 정확하다. context API를 사용해서도 전역상태값을 변경하는 건 물론 가능하지만, context API를 사용해 상태값을 변경하면 provider로 감싸져있는 컴포넌트들이 죄다 렌더링된다는 치명적 단점이 있다! (provider 하위에서 context를 구독하는 모든 컴포넌트는 provider의 value가 바뀔 때마다 다시 렌더링된다는 말)

 

// ContextTest.jsx

export const myContext = createContext("JOFE");

const ContextTest = (props) => {
    const [name, setName] = useState("JOFE");
    
    return (
        <myContext.Provider value={[name, setName]}>
            <Welcome />
            <Hello />
        </myContext.Provider>
    )
}

 

// Welcome.jsx

const Welcome = (props) => {
    const [name, setName] = useContext(myContext)
    return (
        <div>
            <button onClick={() => {setName("Nunu")}}>이름바꾸기</button>
            {name}
        </div>
    )
}

 

// Hello.jsx

const Hello = (props) => {
    useEffect(() => {
        console.log("Hello 렌더링")
    })

    return (
        <>
        </>
    )
}

 

myContext라는 context의 value로 name이란 상태와 name을 변경해주는 세터함수를 넣어줬다. 그리고 이 context를 Welcome컴포넌트에서 사용하는 모습이다. Hello컴포넌트는 useEffect를 사용해서 렌더링될때마다 console에 Hello 렌더링이란 문구를 찍어준다.

 

 

이름바꾸기를 하면?

 

 

myContext를 사용하지 않는 Hello컴포넌트도 단순히 provider 안에 있다는 죄(?)로 다시 렌더링이 되는 모습을 확인할 수 있다..!

 

바로 여기서 Recoil이 이런 문제들을 해결해줄 수 있기 때문에 사용한다. 하단에서 보여드림.

 

Recoil 기초적인 사용법

일단 상위 컴포넌트에서 RecoilRoot란 컴포넌트로 애들을 감싸주면 된다.

 

import { RecoilRoot } from 'recoil';

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

 

그리고 atoms.js파일을 만들어서 요로코롬 atom들을 만들어준다.

※ atom = Recoil에서 사용하는 상태들의 명칭이자 단위라고 생각하면 됨. 이 atom들의 key들은 각각 고유한 값이어야 함! 중복되면 안 된다는 뜻

 

// atoms.js

import { atom } from "recoil";

export const nameState = atom({
    key: "name",
    default: "JOFE"
});

 

참고로 굳이 atoms.js에 만들 필요는 없는데 이렇게 전역상태들을 한 파일에 관리해주는 게 더 편하다고 한다.

 

// RecoilTest.jsx

const RecoilTest = (props) => {
    return (
        <div>
            <Welcome />
            <Hello />
        </div>
    )
}

 

 

// Welcome.jsx

const Welcome = (props) => {
    const [name, setName] = useRecoilState(nameState)
    return (
        <div>
            <button onClick={() => {setName("Nunu")}}>이름바꾸기</button>
            {name}
        </div>
    )
}

 

요로코롬 useRecoilState를 사용해서 React의 hook마냥 쓸 수 있다! React스럽다는게 최고 장점인 듯. 참고로 세터함수는 필요없고 값만 읽고 싶다면 useRecoilValue를 쓰면 된다.

 

암튼, 이렇게 하면

 

 

 

요로코롬 Hello컴포넌트는 리렌더링되지 않는다! 오직 해당 atom을 사용하는 애들만 바뀐다.

 

 

※ 참고한 글https://hong-jh.tistory.com/entry/Context-API%EB%8A%94-%EC%99%9C-%EC%93%B0%EA%B3%A0-%EA%B7%B8%EB%A0%87%EB%8B%A4%EB%A9%B4-Redux%EB%8A%94-%ED%95%84%EC%9A%94%EC%97%86%EC%9D%84%EA%B9%8C

 

Context API는 왜 쓰고, 그렇다면 Redux는 필요없을까?

안녕하세요 오늘은 제가 평소에 궁금했던 주제로 글을 써보려고 합니다. Context API의 기능과 왜 사용하는지, Context API의 리렌더링 이슈란 무엇인지 그리고 Redux를 대체할 수 있는지. 위 내용을 설

hong-jh.tistory.com

 

+ Recent posts