'useState'
웹/앱 개발 시 정말 많이 사용하게 되는 상태관리 라이브러리이다.
그리고 Javascript를 사용할 때 정말 혁신적이다고 항상 생각하는 tool 중 하나이기도 하다.
하지만 이 useState 형제들에게도 한계가 있는데,
바로, 한 컴포넌트에서 저장한 state를 다른 컴포넌트에서도 사용하려고 할 때 props로 전달해야 하는 불편함이 있다는 것이다.
props에 대한 설명은 이게 '딱'인 것 같아 참고용으로 가져와봤다!!
우리가 페이지를 여럿 만들다 보면 리액트 페이지 간에도 부모-자식 관계가 생기게 된다.
예를 들어보자면,
App.js (React 만들 때 가장 상위 DOM인 컴포넌트)에서 로그인했을 때 설정하는 이름 정보를 mypage.js 컴포넌트로 가져가야 한다고 하자. 이 예가 상위 컴포넌트에서 하위 컴포넌트로 들어가는 것이라고 볼 수 있다.
상위-하위 컴포넌트 간 데이터를 전달할 시,
1. 상위 -> 하위로 데이터를 전달할 때는 props(속성을 뜻하는 properties를 생각하자)를 이용한다.
예시를 한 번 보자. props 설명을 위해서 간단하게 구성해보았다.
버튼을 누르면 1. 내가 input에 넣은 정보와 2. 버튼을 눌렀는가에 대한 정보가 props로 옮겨가 밑에 이름을 띄울 수 있게 되는 로직이다.
//App.js
import './App.css';
import {useState} from 'react';
import Mypage from "./Mypage";
function App() {
const [username, setUsername] = useState('');
const [click, setClick] = useState('false');
const onChange = (e) => {
setUsername(e.target.value)
};
const onClick= (e)=> {
setClick('true');
}
return (
<div className="App">
<h1>이름을 입력하세요</h1>
<div>
<input onChange={onChange}/>
<button onClick={onClick}>이름 설정</button>
</div>
<Mypage click={click} userName={username}/>
</div>
);
}
export default App;
//Mypage.js
import React from 'react'
const Mypage = ({click,userName}) => {
console.log(click)
if (click==='true')
return (
<div>
<p>안녕하세요, {userName}님!</p>
</div>
)
}
export default Mypage;
2. 반대로 하위->상위 컴포넌트로 데이터를 전송하고 싶을 땐 어떻게 해야 할까??
자연스럽게 이런 방법을 떠올려 볼 수 있는데,
1. 하위 컴포넌트에서 props를 만들어 상위컴포넌트에 전달하기
2. 그냥 방금처럼 상위컴포넌트에 props를 만들고 하위 컴포넌트에서는 불러와 사용하기
답은..!! 2번이당
그럼 이제 useState의 한계가 보인다.
이렇게 항상 상위하위 관계를 계속 따지면서 구현하는 것은, 페이지가 작은 웹/앱에서는 유용할지 몰라도 컴포넌트 깊이가 클 경우에는 매우 불리할 수 있다. 이 때 사용할 수 있는 것이 바로,
recoil + atom 이다. (동적으로 전체 하위트리가 다시 마운트되는.. 어마어마한 툴!)
우리가 쇼핑 사이트에서 활동할 때 로그인되어 있는 내 이름은 '결제 페이지', '후기 작성 페이지', '댓글창' 등등 수많은 페이지에서 필요한 정보이다. 이럴 때 유용하다고 볼 수 있다.
그럼 한 번 내가 구현한 로그인 로직에서 설명을 해보려고 한다.
useState(''); 또는 useState('false'); 에 해당하는 '', 'false'는 초기상태를 뜻한다. recoilState에서는 이를 atom으로 지정할 수 있는데, 기본적으로 이런 모양새를 띠며 주로 src/store/atom.js 처럼 저장(store) 폴더 안에 설정하도록 하자.
//src/store/store.js
import {atom} from "recoil";
export const usernameAtom = atom({
key : "username", //주로 useRecoilState에서 지정할 변수명으로 설정
default : null,
});
atom으로 감싸 key와 default값을 준다. key는 아래에서 볼 수 있듯, useRecoilState를 쓸 때 지정할 변수 명
[username, setUsername] = useRecoilState(usernameAtom) ;에서 배열의 앞쪽 부분 으로 주로 지정한다.
//App.js
import {RecoilRoot, useSetRecoilState,useRecoilValue, useRecoilState} from 'recoil';
//생략
const setAuth = useSetRecoilState(authState);
const [username, setUsername] = useRecoilState(usernameAtom)
const setIsLoggedIn = useSetRecoilState(isLoggedInState);
//주요 코드
useEffect(()=>{
const unsubscribe = auth().onAuthStateChanged((authUser) => {
if (authUser) {
setAuth(authUser)
console.log('authUser:',authUser);
console.log('이름이닷:',authUser.displayName)
setUsername(authUser.displayName)
setIsLoggedIn(true);
} else {
setIsLoading(false);
}
});
return () => unsubscribe();
},[])
위 코드는 firebase와 연동해 아이디를 가져오는 과정인데, firebase와 관련한 method는 시중에 많이 나와있으므로.. 나중에 중요한 메소드만 한 번 다룰 생각이다(subscribe 등)😙
이렇게 google로그인과 연동해 authUser가 누구인지를 가져올 수 있다. console.log로 출력한 값은 다음과 같다.
//Goal.js (Mypage 부분이라고 생각하면 된다)
import { View, Text } from 'react-native'
import React, {useState} from 'react'
import {usernameAtom} from "../../store/store";
import {useRecoilState} from 'recoil';
const Goal = () => {
//1:03:47
const [username, setUsername] =useRecoilState(usernameAtom); //이렇게 선언해주는 공간에서도 써줘야 됨 잊지 말자
return (
<>
<Text>
안녕하세요, {username} 님,👋
</Text>
</>
)
}
export default Goal;
이제 정보를 출력하면 되는데,
이때 명심해야 하는 건 정보를 가져온 후의 창에서도 useRecoilState로 저렇게 [username, setUsername]을 명시한 후 가져와야 한다는 것이다.
이걸 응용해서 더 많은 것들을 해볼 예정이다!! ><><