리액트 네이티브

context는 별도의 파일에서 관리해야겠어요

발전생 2021. 8. 19. 12:04

App.js에서 시작하자마자 로그인 여부를 확인하려고 App 파일에 코드를 전부 작성했습니다.

const AuthContext = createContext(null);

export default function App() {
  const [state, dispatch] = useReducer(
    (prevState, action) => {
      switch (action.type) {
        case "SET_TOKEN":
          return {
            ...prevState,
            token: action.token,
          };
      }
    },
    {
      // isLoading: true,
      token: null,
      loginFailed: false,
    }
  );

  const authMethods = useMemo(
    () => ({
      signIn: async (email: string, password: string) => {
        try {
          // 로그인 요청 해서 토큰 받기
          const { token } = await login(email, password);
          // 비밀 저장소에 토큰 저장
          await SecureStore.setItemAsync("access_token", token);
          // state의 토큰 변경
          dispatch({ type: "SET_TOKEN", token });
        } catch (err) {
          // 토큰이 안 왔으면 = 로그인 성공 못 함
        }
      },
      signUp: async (email: string, password: string, nickname: string) => {},
    }),
    []
  );

  useEffect(() => {
    const get_saved_token = async () => {
      try {
        const token = await SecureStore.getItemAsync("access_token");
        dispatch({ type: "SET_TOKEN", token });
      } catch (e) {
        // 저장된 토큰이 없을 시
      }
    };
    get_saved_token();
    return () => {
      // 앱 종료 시 state에서 토큰 제거
      dispatch({ type: "SET_TOKEN", token: null });
    };
  }, []);
  
  return (
    <AuthContext.Provider value={authMethods}>
      <NavigationContainer>
        {state.token == null ? <Auth /> : <Main />}
      </NavigationContainer>
    </AuthContext.Provider>
  );
}

 

하지만 warning을 만나게 됩니다.

Require cycle: App.tsx -> navigations\AuthStack.tsx -> screens\SignInScreen.tsx -> App.tsx

 

로그인 화면을 띄워주는 파일에서 이 부분이 문제였습니다. App에서부터 렌더링하기 시작했는데 App을 또 import 하고 있었으니까 문제가 됐던 겁니다.

import { AuthContext } from "../App";
import React, { useState, useEffect, useContext } from "react";
import { View, Button } from "react-native";
import { TextInput } from "react-native-gesture-handler";
import { AuthContext } from "../App";

const SignInScreen = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const { signIn } = useContext(AuthContext);

  return (
    <View>
      <TextInput placeholder="이메일" value={email} onChangeText={setEmail} />
      <TextInput
        placeholder="비밀번호"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
      />
      <Button title="로그인" onPress={signIn(email, password)} />
    </View>
  );
};

export default SignInScreen;

 

그럼 이제 context를 App이 아닌 다른 파일로 옮겨야 하겠죠?

그래서 저는 createContext 함수만 다른 파일로 옮겨보기로 합니다. hook는 함수형 컴포넌트 안에서만 사용할 수 있기 때문에 리듀서 함수, useMemo를 사용하는 context 디폴트 값은 옮기는 게 불가능해 보였습니다.

 

AuthContext.ts

import { createContext } from "react";

const AuthContext = createContext(null);
export default AuthContext;

 

이제 warning 없는 화면을 보실 수 있습니다.