리코일 개념을 정리하는 포스팅이다.
위 화면은 클릭일 때에는 배경색을 파란색으로 변경하고 검정색 바를 오른쪽으로 이동시키는 기능을 보여준다.
배경색 파란색으로 변경하기
클릭되지 않았을 때의 배경색을 #111
으로 지정하는 스타일을 작성하고 클릭되었을 때 배경색을 #20b7ff
으로 지정하는 스타일를 하나 더 작성한다.
검정색 바 오른쪽으로 이동 시키기
클릭되지 않았을 때에는 left:0
으로 왼쪽에 위치하도록 스타일을 지정하고 클릭되었을 때에는 left:40px
로 오른쪽으로 40px
이동하도록 스타일를 하나 더 작성한다.
웹에서는 화면에 보여주고 싶은 상황에 따라 여러 스타일시트를 작성하고 그 상황에 맞는 상태
를 만들어 상태값을 이용해서 상황에 맞는 스타일시트가 적용되도록 한다.
즉, 여러 상황에 맞는 다양한 화면을 보여주기 위해서 상태가 필요하다.
리액트(React)는 왜 쓰는 건데⁉
-리액트에 대한 자세한 내용은 이 링크를 참고해주세요.
이미지 : Redux가 필요하다는 것을 언제 알 수 있나요?
리액트에서는 가상돔(Virtual DOM)을 이용해 변경된 상태를 파악해서 이전과 다르게 변경된 상태를 화면에서 다시 그려준다.(다시 랜더링한다)
변경된 곳만 다시 화면을 그려주면 화면 전체가 깜빡이는 것을 없애주어서 사용자 경험을 향상 시켜준다. 또 화면 전체를 다시 그릴 때보다 더 적은 브라우저의 자원을 활용하기 때문에 빠르고 쾌적한 사용자 경험을 제공한다.
리덕스(Redux)는 왜 쓰는 건데⁉
-리덕스에 대한 자세한 내용은 이 링크를 참고해주세요.
리액트의 상태를 이용해 화면의 변화를 줄 수 있지만 프론트엔드의 프로젝트가 점점 커지면서 그 상태가 너무 많아졌다. 그래서 상태를 체계적으로 관리해야 하는 필요성이 대두되었다.
그래서 리덕스가 탄생하였고 대부분의 개발자들이 리액트를 사용하면서 상태관리를 별도의 라이브러리를 이용해 관리하기 시작했다.
위의 그래프는 stateofjs
의 2020년 조사 중에 Data Layer Usage
항목이다. 상태 관리를 위해서 많은 라이브러리를 사용 중이고 그 중에서 Redux
는 많은 비중을 차지하고 있다.
이미지 : Redux가 필요하다는 것을 언제 알 수 있나요?
리덕스를 간단하게 설명하면 위의 그림과 같다. 상태가 변경되면 액션을 통해서 리듀서에 전달되고 리듀서에서 상태를 변경해 스토어에 저장된다. 스토어에서 상태가 변경되면 해당 상태를 사용(구독)하고 있는 컴포넌트에 변경된 상태를 전달해준다.
위의 첫번째 그림은 상태 관리 라이브러리의 만족도에 대한 조사결과이고, 두 번째 그림은 이후 3년 안에 사라질 것으로 예상되는 기술에 대한 질문의 결과이다.
리덕스의 만족도는 급격하게 떨어졌고 3년 이후 사라질 기술 1위로 리덕스가 꼽혔다.
리덕스의 단방향의 흐름은 상태를 디버깅하게 쉽게 해주지만 action, reducer, selector, store를 초기에 세팅하는 것은 엄청나게 번거로운 일이고 많은 코드를 추가하도록 강제한다. Redux Saga 이후 redux-toolkit이라는 라이브러리가 나와서 코드를 줄여주고 간단해지긴 했지만 그래도 초기에 세팅은 여전히 번거롭고 리액트와의 궁합은 만족스럽지 못하다.
A state management library for React
리코일을 설명하는 리코일 팀의 표현이다.
리액트를 위한 상태 관리 라이브러리
We want to improve this while keeping both the API and the semantics and behavior as Reactish as possible.
Recoil은 API, 의미, 동작을 최대한 리액트스럽게 유지하며 이를 개선하고자 한다.
페이스북에서 만든 리액트에서는 리덕스,Mobx처럼 상태 관리를 도와주는 기능이 없었다. Context API가 있긴 하지만 페이스북에서는 Context API를 이용해 상태를 관리하는 방식은 어렵다고 판단했다.
개인적인 요약으로는 new context가 (locale/theme와 같은) 낮은 빈도의 업데이트에서는 사용될 준비가 되어 있다는 것입니다. 이전 context가 사용 된 것과 동일한 방식으로 사용하는 것도 좋습니다. 즉 정적 값의 경우 구독을 통해 업데이트를 전파합니다. 하지만 모든 Flux와 비슷한 상태 관리의 대체물로 사용할 준비가 되어 있지는 않았습니다.
Context API를 사용해서 상태 관리를 하면 부분적인 상태 변경이 어려워진다. 별도의 Provider
를 이용해 랜더링을 제어할려고 해도 자식 요소들 전체가 다시 랜더링해야 하고 의도치 않은 커플링이 생기는 문제가 생긴다.
반면 Redux와 Mobx의 기능적인 문제는 없다. 하지만 이 상태 관리 라이브러리들은 리액트의 내부 라이브러리가 아니기 때문에 리액트의 가상돔의 내부 로직과는 별개로 동작한다. 그러니까 Redux의 store은 리액트의 상태와는 별개의 것이기 때문에 우리는 수많은 코드를 통해서 리액트의 상태와 리덕스의 상태를 일치시키는 작업을 해야 했다. 하지만 리코일은 다르다. hook처럼 리액트의 상태를 간단하게 변경하고 이용 가능하다.
Atom
은 상태이다. 리액트의 state
,props
와 비슷하지만 리덕스의 store의 상태들처럼 구독할 수 있고 Atom
의 상태가 변경되면 구독하고 있는 컴포너트들의 다시 랜더링되면서 변경된 Atom
의 상태를 공유한다.
Atom
은 고유한 키값과 기본값을 가진다. 고유한 키값을 이용해서 필요한 컴포넌트에서 Atom
를 사용할 수 있고 기본값은 초기값이 된다.
useRecoilState
은 hook의 useState
와 사용하는 방식이 동일하다. 배열 첫번째 요소에 상태의 값이 들어가고 두번째 요소에 상태를 변경할 수 있는 함수가 들어간다. 차이점은 이 변경된 상태가 자동으로 전역으로 상태가 공유된다는 것이다. 구독이나 연결과 같은 작업은 필요없다. useRecoilState
을 사용한 Atom
의 상태는 이 상태를 사용하고 있는 다른 컴포넌트와 자동으로 공유된다.
useRecoilValue
는 상태를 변경하는 함수없이 Atom
값만 받는다.
여러 상태를 이용해 값을 표현할 때가 있다. 이러한 상황에서는 각각의 상태가 변경될 때, 이 값 또한 즉각적으로 변경되어야 한다. selector
는 순수함수로서 Atom
이나 또 다른 selector
를 이용해서 새로운 데이터를 전달해줄 수 있다. selector
를 이용하면 연관된 Atom
과 selector
가 변경되면 그 따른 변경된 값을 즉시 받을 수 있고 이 selector
를 사용하는 컴포넌트도 다시 랜더링된다. selector
에서는 async
를 이용해 비동기 작업 또한 가능하다. 서버에서 api로 데이터를 불러오는 것도 가능하다.
selector
또한 고유한 키값을 갖는다. get
에는 반환 값을 만들어주면 된다. 위에 예시에는 cartState
, shippingState
를 이용해서 최종 가격을 연산하는 로직을 만들었다.
사용할 컴포넌트에서는 useRecoilValue
를 이용해서 get
에서 리턴되는 값을 받으면 된다. 아직까지는 selector
를 useRecoilState
와 함께 사용할 수 없다.selector
의 값은 읽기전용으로만 사용 가능하다.(추후에 업데이트 될지도?)
cartState
,shippingState
,inventoryState
카트, 배송지, 창고재고를 나타내는 상태를 만들었다.
inventoryState
는 서버에서 불러오는 값으로 음료의 종류를 나타낸다.
음료 이름, 가격, 카테고리, 가격 등의 정보를 담은 atom
이다.
cartState
는 사용자가 ADD
버튼을 이용해 장바구니에 담을 경우 담기는 데이터이다.
shippingState
는 배송지 정보로 SHIPPING 영역에서 변경 가능한 데이터이다.
이 세가지 상태가 DRINKS, CART, SHIPPING, TOTALS 화면 영역에 각각 변화를 주고 있다. 각 영역은 각각의 컴포넌트로 분리해두었다.
마침 Recoil을 공부하고 있었는데 참고가 됐습니다! 좋은 글 감사합니다.