ReactNative로 러닝어플 만들기 - 내비게이션 구조, 로그인, 회원가입

이은지·2022년 4월 6일
0
post-thumbnail

🔥 BurnIN!!!! 👟🔥

학회에서 ReactNative를 사용한 앱 개발을 하게 됐다. 완성 다 하고 나서 컴포넌트들 뜯어가며 기록하는 건 정말 어려운 일이기 때문에, 구현 중간중간에 기록 하려고 한다.

구현 목표는 러닝어플이다. 구글 플레이스토어 등록까지가 목표! 구현할 기능은 다음과 같다.

  • 사용자의 러닝을 트래킹(칼로리, km 등)
  • 개인 러닝 기록을 시각화한 대시보드
  • 앱 배포 기간 동안 러닝에 참여한 모든 참가자들의 기록과 관련된 대시보드(랭킹 등)
  • 위의 기능을 위한 로그인, 회원가입 기능

NikeRunClub과 같은 기존 러닝어플의 미니버전을 제작하는 느낌이다.
백엔드(2), 프론트엔드(1), 기획 및 시각화(1) 이런 멤버 조합으로 재밌는 걸 만들어보자! 해서 시작하게 됐다 🤗 ( 땡스투 JW& SJ )

🧑🏻‍✈️ Navigation Structure

전체 구조

StackNavigator와 TabNavigator 이렇게 두 가지를 사용했다. 리액트에서 서브라우팅을 했듯이 루트 스택 내비게이터 안에 또다른 스택 내비게이터와 탭 내비게이터를 두었다.

SignUpStack

회원가입의 경우 총 4가지의 정보를 입력 받아야 하는데, 요즘 어플들처럼 여러 페이지에 걸쳐서 입력을 받고 싶어서(왠지 그게 멋져) SignUpStack을 따로 두었다.

SignUpStack의 initialRouteName 으로 'GetId'를 지정해놓아서, 회원가입 화면으로 이동 시 GetId 컴포넌트가 렌더링된다. Get<정보> 컴포넌트마다 버튼이 있다. 사용자가 버튼을 클릭하면 navigation.navigate('Get<다음정보>') 를 통해 다음 컴포넌트로 이동한다.

MainTab

메인 화면의 경우 하단탭을 이용해 화면 전환이 가능하도록 했다.

🐚 로그인

토큰 발급

로그인/회원가입 성공 시 서버에서 토큰을 보내준다.
해당 토큰을 token이라는 key로 AsyncStorage에 저장해둔다.

토큰 유무에 따른 화면 분기

사용자가 앱에 접속- LandingScreen이 처음으로 렌더링됨

LandingScreen에서는 아래와 같은 작업이 이뤄진다.
사용자 기기의 AsyncStorage에서 token이라는 key를 확인한다.

  • value가 존재하면 => MainTab으로 이동
  • value가 존재하지 않으면 => LoginScreen으로 이동

LoginScreen 에는 회원가입하기 버튼이 있어 계정이 없는 경우 회원가입을 할 수 있다.

🪨 회원가입 with Context API

구현 목표와 고려했던 방안들

회원가입 과정에서 총 4가지의 정보를 입력 받아야 하는데, 위에서 이야기했듯 각 정보를 별개의 컴포넌트에서 입력을 받는다. 이때 마지막 정보를 입력 받는 컴포넌트에서 4가지 정보를 한 번에 서버로 전송해야 한다. 이말인즉슨 컴포넌트 간 정보 공유가 필요하다는 뜻.

보통 컴포넌트 간 정보를 주고 받을 때 props를 사용하는데, 정보 입력 컴포넌트들의 경우 서로 부모-자식 관계가 아닌 같은 레벨에 있는 병렬적 관계이다. 따라서 props가 아닌 다른 방법을 사용해야 했음. 이를 구현하기 위해 고려했던 방안들에는 다음과 같은 것들이 있다.


  1. 라우터 파라미터 사용하기

    맨 처음에는 navigation.navigate함수로 다음 컴포넌트 이동 시 파라미터에 정보를 넣는 방법을 생각해봤다. 그러나

    • 라우터 파라미터의 본래 용도에 어긋난다는 점
      (새로운 화면을 보여줄 때 의존해야 하는 값이 있는 경우 라우터 파라미터를 사용한다고 배웠다.)
    • 매 파라미터마다 route 객체로 파라미터를 받아온 다음, 새로운 정보를 추가해 또다시 파라미터로 넘겨주어야 한다는 점

    이 두 가지 이유 때문에 이 방법은 기각시켰다.

  2. SignUpStack컴포넌트의 state로 모든 데이터를 저장

    Get<정보> 컴포넌트 내에 바로 TextInput 태그가 있는 게 아니고, SignUpInput 이라는 컴포넌트를 import해서 사용한다. 결국 이 방식을 사용하려면 state의 세터 함수를 두 컴포넌트에 걸쳐 props로 전달해줘야 한다. 또한 그때마다 불변성을 지키며 상태 객체를 업데이트 해줘야 한다는 점이 불편해서 기각.

  3. Redux
    리덕스를 사용하기에는 프로젝트 크기가 작아서 기각.

  4. Context API

    회원가입을 하고 나면 다른 컴포넌트에선 이 정보들에 접근할 일이 없다.
    (AsyncStorage에 저장해둘 예정이기 때문에)

    그리고 ContextAPI의 경우 ContextProvider로 감싼 컴포넌트들만 그 정보에 접근할 수 있다. 이 점이 위의 특징에 적합하다고 생각했다.


Context API를 이용한 구현

📂 contexts > SignUpContext.js 파일을 만들어서, 그 안에 SignUpContextProvider를 정의했다. 그 다음 SignUpStack.js의 모든 컴포넌트를 SignUpContextProvider 태그로 감쌌다.

이로써 SignUpStack의 모든 하위 컴포넌트들(정보를 입력 받는 컴포넌트들)이 SignUpContextProvider 의 state인 form에 접근할 수 있게 되었다.

import React from 'react';
 import {createContext, useState} from 'react';

 const SignUpContext = createContext();
 export function SignUpContextProvider({children}) {
   const [form, setForm] = useState({
     id: '',
     password: '',
     confirmPassword: '',
     nickname: '',
     height: '',
     weight: '',
   });

   const createChangeTextHandler = name => value => {
     setForm({...form, [name]: value});
   };

   return (
     <SignUpContext.Provider value={{form, createChangeTextHandler}}>
       {children}
     </SignUpContext.Provider>
   );
 }

 export default SignUpContext;

구체적으로 ContextAPI를 어떻게 활용했는지는 다음 포스팅에 나눠서 작성하도록 하겠다.

profile
교육학과 출신 서타터업 프론트 개발자 👩🏻‍🏫

0개의 댓글