[React]recoil 라이브러리
recoil로 상태 관리하기
Main 화면
메인 화면은 이렇게 생겼다. 리스트에서 식당을 눌렀을 때 또는 지도에서 마커를 눌렀을 때 같은 식당인지 어떻게 확인할까?
1. props로 값 넘겨주기
Main에서 선택된 식당을 관리하고 List와 Map 컴포넌트에 props로 전달해주면 된다.
2. recoil로 전연 변수 관리하기
이 프로젝트에서는 recoil로 선택된 식당을 전역으로 관리했다. 아래에 그 방법을 설명해두었다.
설치
npm install recoil
RecoilRoot
App.js
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import BrowserMain from "./pages/Main/BrowserMain";
import { RecoilRoot } from "recoil";
function App() {
return (
<RecoilRoot>
<div className="App">
<BrowserRouter>
<div className="browser-main">
<Routes>
<Route path="/" element={<BrowserMain />} />
</Routes>
</div>
</BrowserRouter>
</div>
</RecoilRoot>
);
}
export default App;
Atom
- Atom은 상태(state)의 일부를 나타낸다.
- Atoms는 어떤 컴포넌트에서나 읽고 쓸 수 있다.
- atom의 값을 읽는 컴포넌트들은 암묵적으로 atom을 구독한다. 그래서 atom에 어떤 변화가 있으면 그 atom을 구독하는 모든 컴포넌트가 재 렌더링 되는 결과가 발생할 것이다.
atom.js
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
} from "recoil";
import { recoilPersist } from "recoil-persist";
const { persistAtom } = recoilPersist();
export const selectStore = atom({
key: "selectStore",
default: null,
effects_UNSTABLE: [persistAtom],
});
Selector
- Selector는 파생된 상태(derived state)의 일부를 나타낸다.
- 파생된 상태는 상태의 변화다. 파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다.
프로젝트에서는 사용하진 않았지만 리코일의 주요 기능이므로 넣었다. Recoil은 변수만 관리하는게 아니라 함수처럼 사용할 수도 있다.
import { atom, selector } from "recoil";
export const wonState = atom({
key: "wonState",
default: 0,
});
export const dollarState = selector({
key: "dollarState",
get: ({ get }) => get(wonState) / 1400,
set: ({ set }, dollar) => set(wonState, dollar * 1400),
});
컴포넌트 적용
CheckStore.js
import React from "react";
import { useRecoilState } from "recoil";
import { selectStore } from "../../../../Atom";
const CheckStore = (props) => {
const [checkedStore, setcheckedStore] = useRecoilState(selectStore);
//선택했을 때
const clickStore = () => {
setcheckedStore(store.id);
};
return (
<div key={store.id} onClick={clickStore}>
<!-- 리스트 한개 요소 -->
</div>
);
};
export default CheckStore;
Map.js
import { useState, useEffect, useRef } from "react";
import { useRecoilState } from "recoil";
import { selectStore } from "../../../Atom";
function Map() {
const { naver } = window;
const mapElement = useRef(null);
const [store, setStore] = useRecoilState(selectStore);
// 지도
useEffect(() => {
if (!mapElement.current || !naver) return;
const location = new naver.maps.LatLng(centerLat, centerLong);
const mapOptions: naver.maps.MapOptions = {
//생략
};
const map = new naver.maps.Map(mapElement.current, mapOptions);
//식당 위치
for (let i = 0; i < stores.length; i++) {
//지오코딩(주소->좌표)
naver.maps.Service.geocode(
{ query: stores[i].address },
function (status, response) {
if (status === naver.maps.Service.Status.ERROR) {
return alert("문제가 발생했습니다.");
}
//마커 찍기
const otherMarkers = new naver.maps.Marker({
//생략
});
//정보창
const infowindow = new naver.maps.InfoWindow({
//생략
});
//마커 클릭하면 정보창 뜨게함
naver.maps.Event.addListener(otherMarkers, "click", function (e) {
setStore(stores[i].id); //이 부분이 식당 선택
});
if (store === stores[i].id) {
infowindow.open(map, otherMarkers);
} else {
infowindow.close();
}
}
);
}
}, [store]);
return <div ref={mapElement} />;
}
export default Map;
import recoil과 Atom.js에서 가져올 값
문법
위 코드 설명
결과보기
리스트에서 ‘소바쿠’를 선택했을 때도 지도에서 해당 식당의 정보창이 열리고,
지도에서 ‘요마시’를 선택했을 때도 리스트에서 해당 식당이 선택되어진 걸 볼 수 있다.
댓글남기기