[리액트] Recoil , localStorage 같이 사용하기 (localStorageEffect)

zhflsdl보보·2023년 8월 20일
1

React

목록 보기
7/7

이번 DdokD 똑디 프로젝트를 초기 세팅하면서, 상태관리를 어떻게 할 것인지에 대한 논의를 하게되었다.

해당 서비스는 노인들을 위한 스마트폰 교육 플랫폼이다. 주요 기능으로는 회원가입, 로그인, 레벨 테스트가 있다.

플랫폼 자체가 유저에게 받아야할 데이터와 관리해야 할 데이터들이 많지 않았기 때문에 어떤게 나을지에 대한 고민을 했다.

아예 사용하지 않고 로컬에서만 하자니, 코드도 난잡해지고 다른 페이지에서 가져다 쓸 내용이 조금 있었기 때문에 라이브러리를 쓰는 것이 좋겠다고 의견이 모아졌다.

Redux? or Recoil?

그렇게 많은 데이터를 저장할 필요는 없었기에 무거운 Redux 대신 Recoil을 선택하였다.

Recoil 초기 세팅

설치는 간단하다. 내가 사용하고자 하는 프로젝트에서 install 하여 설치해주면 된다.

npm install recoil

그리고, 가장 부모 컴포넌트에서 아래와 같이 써주면 된다.

나는 Index.tsx 에 작성해주었다.

const root = ReactDOM.createRoot(
	document.getElementById('root') as HTMLElement,
);
root.render(
	<React.StrictMode>
		<RecoilRoot>
			<ThemeProvider theme={theme}>
				<App />
				<GlobalStyle />
			</ThemeProvider>
		</RecoilRoot>
	</React.StrictMode>,
);

그러면 사용할 준비는 끝났다.

이제, Atom 파일을 만들어준다.

Atom은 상태(state)의 일부를 나타낸다. Atoms는 어떤 컴포넌트에서나 읽고 쓸 수 있다. atom의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독한다. 그래서 atom에 어떤 변화가 있으면 그 atom을 구독하는 모든 컴포넌트가 재 렌더링 되는 결과가 발생할 것이다.

Recoil 공식문서에 잘 나와있어서 참고하면 아주 좋다.

컴포넌트에서 사용할 때는 리액트 훅인 useState 처럼 사용하면 되기 때문에 전혀 어렵지 않다.


Trouble Shooting

내가 맡은 파트는 로그인, 회원가입 부터 해서 새로운 유저 정보 받는 파트이다.

유저 정보를 약 10가지의 정보를 여러페이지에 걸쳐서 받는다.
그리고 그 정보들을 가지고 있다가 마지막 페이지에서 백엔드 Api를 호출하여 보내주게 된다.
계속 페이지가 달라지고, 전 페이지의 정보를 다음 페이지에서 불러서 보여주는 경우가 있기 때문에 useState로만 이 많은 데이터들을 저장하기에는 무리가 있었다.
이 과정에서 Recoil을 사용하려고 했다.

Recoil은 전역으로 데이터를 가져다 쓸 수 있기 때문에 이전 페이지의 데이터를 그 다음 페이지에서 가져다 쓰는 것은 문제가 없었다.
하지만, 새로고침하면 정보가 다 날라가는 큰 문제가 있었다.

이 문제를 해결하기 위해, localStorage 를 같이 사용하기로 했다.
localstorage는 새로고침 하거나, 창을 닫더라도 데이터가 사라지지 않고, 쿠키보다 용량이 커서 선택하게 되었다.

처음에는 다음 버튼을 누르면 Recoil로 저장하고, 그 데이터를 localStorage에 한 번 더 저장했다. 그리고 이전 페이지에서 입력한 값이 페이지 이동 후 다시 돌아왔을 때 보여주게 하기 위해서 useEffect를 사용해서 localstorage에 저장되어있는 값을 다시 불러오는 방법을 생각했다.

그러다 보니 불필요한 코드들이 많아졌고, 페이지마다 useEffect를 호출해야 하고, 데이터가 최신화되지 않을 수 있다는 생각을 하게되었다.


localStorageEffect?

다시, 공식문서도 읽고 구글링을 하다보니 localStorageEffect라고 Recoil의 atomlocalStorage를 자동으로 연동시키는 방법이 있었다!! 유레카

atom의 effects 가 atom이 실행될 때 부수적으로 실행되는 것이다.

아래가 해당 코드이다.

// Recoil & Localstorage
const localStorageEffect =
	(key: string) =>
	({ setSelf, onSet }: any) => {
		const savedValue = localStorage.getItem(key);

		// setSelf: atom 값 설정
		if (savedValue !== null) {
			setSelf(JSON.parse(savedValue));
		}

		// atom의 변화가 감지될 때 작동하여 storage에 저장, setSelf에 의해서는 작동X
		onSet((newValue: any, _: any, isReset: boolean) => {
			isReset
				? localStorage.removeItem(key)
				: localStorage.setItem(key, JSON.stringify(newValue));
		});
	};

const applyState = atom<applyTypes>({
	key: 'applyState',
	default: {},
	effects: [localStorageEffect('apply-data')],
});

export default applyState;

아래는 Recoil을 사용한 코드이다.

const [apply, setApply] = useRecoilState(applyState);
const [name, setName] = useState<string>(apply.name || '');
const [phone, setPhone] = useState<string>(apply.phoneNumber || '');

// 다음으로 넘어가는 버튼
const submit = () => {
	setApply({ ...apply, name: name, phoneNumber: phone });
};

이렇게 atom을 설정해주고 필요한 곳에서 간단하게 불러서 사용하면 된다.
useEffect로 데이터를 불러오지 않아도, atom이 구독하고 있기 때문에 페이지 이동후 다시 돌아오더라도 데이터를 보여줄 수 있게 되었다. 그리고 데이터가 최신화되지 않는 걱정을 하지 않아도 된다. 최공


Recoil with Storage (feat. effects)
Atom Effects

profile
매일매일 성장하는 개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 24일

어르신들을 위한 교육 플랫폼이라니 취지가 아주 좋네요

답글 달기