본문 바로가기

Firebase

[인프런] 7. context로 유저정보 관리하기

너네 백엔드 하고 싶은 거 있으면 얼마든지 해 난 괜찮어 왜냐면 나는 파이어베이스가 있어 강의 - 대시보드 | 인프런 (inflearn.com)

 

너네 백엔드 하고 싶은 거 있으면 얼마든지 해 난 괜찮어 왜냐면 나는 파이어베이스가 있어 | 제

제주코딩베이스캠프 | 프론트엔드 개발자인데 로그인 기능을 구현하지 못해 아쉬웠던 적 있으신가요? DB를 이용해 데이터를 저장하고 불러오는 기능을 구현하고 싶지만 쿼리를 공부하기는 부담

www.inflearn.com

 

 

1. 유저 정보를 Context로 관리하기 

 

- 로그인이 된 회원의 정보는 나중에 사용할 firestore 같은 여러 firebase 서비스에서 이용이 가능하다. 

- 또한 로그인한 유저의 정보를 바탕으로 어떤 페이지는 보여지고, 또 보여지지 않은지 등 유저의 접근 등급을 설정할 수 있기 때문에 로그인할 때 받아온 유저 정보를 전역으로 저장할 필요가 있다. 

 

React Context

 

- 일반적인 React 애플리케이션에서 데이터는 부모로부터 자식에게 props를 통해 전달된다. 

- 하지만

 1) 애플리케이션 안의 여러 컴포넌트들에 동일한 props값을 전해줘야 하는 경우

 2) 오로지 하위 컴포넌트로 데이터를 전달하기 위해 중간에 위치한 컴포넌트들에 전달하는 용도로만 쓰이는 props를 사용할 경우 

- 이 과정이 번거로울 수 있다. 

 

- Context는 React 컴포넌트 트리 안에서 데이터를 전역적으로(global) 사용할 수 있도록 고안된 방법이다. 

- Context를 이용하면, 트리 단계마다 명시적으로 props를 넘겨주지 않아도 많은 컴포넌트가 이러한 값을 공유하도록 할 수 있다. 

 

 

1)

- src 폴더에 context 폴더를 생성하고 인증과 관련된 정보를 담을 AuthContext.js 파일을 생성한다. 

 

src/context/AuthContext.js

import { createContext, useReducer } from 'react';

// context를 객체를 생성합니다.
const AuthContext = createContext();

const authReducer = (state, action) => {
    switch (action.type) {
        default:
            return state
    }
}

// context를 객체를 구독할 컴포넌트의 묶음 범위를 설정합니다.
const AuthContextProvider = ({ children }) => {

    const [state, dispatch] = useReducer(authReducer, {
        user: null
    })

    return (
				// { ...state, dispatch } 이 두 가지 값이 context객체를 통해 접근할 수 있는 값이 됩니다.
        <AuthContext.Provider value={{ ...state, dispatch }}>
            {children}
        </AuthContext.Provider>
    )
}

export { AuthContext, AuthContextProvider };

 

 

useReducer

 

- useState의 대체 함수

- 보통 숫자형이나 문자열 같은 간단한 형태의 데이터는 useState를 이용하지만 객체와 같이 복잡한 형태의 데이터를 다룰 때 많이 사용

 

 const [관리할 값, dispatch 함수] = useReducer(리듀서 함수, 관리할 값의 초기화)

 

- 리듀서는 위의 형태로 사용하며, dispatch 함수는 리듀서 함수를 호출하는 역할을 함.

 

 dispatch({type: 'login', payload : user})

 

- dispatch 함수는 위와 같은 형태로 사용.- 전달하는 인자를 action이라고 하며, action에는 type과 전달할 데이터인 payload가 있다. 

 

 

2)

 

- Context 구독 범위를 설정한다. 

 

- index.js로 이동하여 루트 컴포넌트인 <APP />을 Context로 감싸 하위에 있는 어떤 컴포넌트에서든 Context 정보에 접근할 수 있도록 한다. 

 

index.js

import { AuthContextProvider } from './context/AuthContext';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <AuthContextProvider>
      <App />
    </AuthContextProvider>
  </React.StrictMode>
);

 

 

3)

- 우리가 생성한 Context에 값을 쉽게 전달할 수 있도록 훅을 만들어 줌

 

- Hooks 폴더에 useAuthContext.js 파일을 생성한다. 

- context를 사용하기 위한 useContext와 우리가 생성한 AuthContext 두가지를 import 한다. 

 

src/hooks/useAuthContext.js

import { useContext } from 'react' 
import { AuthContext } from "../context/AuthContext";

export const useAuthContext = () => {

    const context = useContext(AuthContext);

    // 이제 context안에는 AuthContext에서 반환하는 state 값(user), dispatch 함수 두 가지가 들어있습니다.
    return context
}

 

 

4)

- 이제 context를 사용하도록 한다. 

- 우선 AuthContext.js에서 dispatch 함수가 실행될 때 전달 받을 수 있는 action의 type을 추가한다. 

 

AuthContext.js

객체 병합 : 기존에 있던 user 정보에 새롭게 받아오는  action의 payload로부터 받아오는 유저정보를 병합하기 위해서 사

switch (action.type) {
    case 'login':
	    //전개구문을 이용해 객체의 user 값을 업데이트 합니다.
        return { ...state, user: action.payload }
    default:
        return state
}

 

 

전개구문을 이용한 객체 병합 

 

-  Name이라는 키, 철수라는 값 , species라는 키, human이라는 값이 들어있는 CurrentState객체가 있다. 

- CurrentState에 새로운 값을 할당하는데 전개구문으로 currentState를 풀어 주고 있다. 

- Name 영희와 age 11이 추가됨 

- 두가지 키 값 쌍은 병합이 됨 

let currentState = { name: '철수', species: 'human'};
currentState = { ...currentState, name: '영희', age: 11}; 

console.log(currentState);
// {name: '영희', species: 'human', age: 11}

 

 

5)

- useSignup.js로 가서 회원가입 후 받아오는 유저 정보를 어디서든 사용할 수 있도록 useAuthContext를 통해 업데이트 하도록 함 

 

useSignup.js

// 상단 useState 아래에 dispatch 함수를 할당하는 상수를 선언합니다.
…

// 에러 정보를 저장합니다.
const [error, setError] = useState(null);
// 현재 서버와 통신중인 상태를 저장합니다.
const [isPending, setIsPending] = useState(false);

// 유저정보를 전역에서 활용할 수 있도록 dispatch 함수를 통해 업데이트합니다.
const { dispatch } = useAuthContext();

…
…

// 프로필을 업데이트하는 함수에 dispatch 함수를 실행하여 우리가 만들었던 authReducer 함수를 호출합니다.
updateProfile(appAuth.currentUser, { displayName })
.then(() => {
// action으로 전달될 인자를 작성합니다.
    dispatch({ type: 'login', payload: user });
    setError(null);user
    setIsPending(false);
}).catch((err) => {
    setError(err.message);
    setIsPending(false)
    console.log(err.message);
});