[react-native]앱이 꺼져도 데이터를 보존하는 방법

WINSCA, Han·2021년 7월 17일
1


앱을 완전히 껐다가 켰을 때, 다시 로그인해야 하면 참 귀찮아진다. 사용자들의 편의를 위해서 요즘 앱들은 껐다가 다시 켜도 로그인되어 있는 화면을 다시 보여주곤 한다.
그렇게 할 수 있는 것은, 앱이 꺼지기 직전에 사용자가 로그인이 되어 있었는지 체크 한 후, 로그인한 적이 있으면(아직 로그아웃하지 않았다면) 바로 메인 화면으로 보내는 로직을 사용하기 때문이다.

그러기 위해선, 앱이 꺼져도 저장/관리한 데이터는 계속 사용할 수 있는 AsyncStorage를 사용해야 한다.

  1. vscode 터미널에서 AsyncStorage 설치하기.

expo install @react-native-async-storage/async-storage

AsyncStorage는 react-native에서 가져와 사용할 수 있는 라이브러리로, 주로 이럴 때 사용한다.

1) 로그인 후 앱을 껐다 켰다 ⇒ 로그인이 되어 있으면 바로 메인 화면 보여주기

2) 글을 작성하다 페이지를 이탈했다 ⇒ 작성 중이던 글을 가져오기

3) 사용자가 좋아요를 눌렀던 게시글이 있다 ⇒ 매번 서버에서 가져오지 않고, AsyncStorage에서 꺼내 관리하기

이렇게 앱이 꺼져도 보존되면 편리한 데이터들을 AsyncStorage에 담아 관리하곤 한다.

  1. AsyncStorage 사용하기.

로그인했을 때 AsyncStorage 통에 로그인한 사용자 이메일을 저장한다. 그럼 이 통을 살펴볼 때 사용자 이메일이 있으면 로그인 한 적이 있다는 뜻이고,

로그아웃했을 때 AsyncStorage 통에 든 이메일을 지운다. 그럼 로그아웃 시 이 통을 조사했을 때, 아무것도 안 나오는 것이다.

순서로 살펴보자면,

1) SignInpage에서 화면이 그려진 다음 useEffect가 실행된다

2) useEffect에서 AsyncStorage 속 session 통을 살펴본다

3) 이메일이 들어 있다면 TabNavigator로 보낸다

4) 이메일이 들어 있지 않다면 Loading 화면을 끄고 로그인 화면을 보여준다

간단하쥬~? :)

  1. firebaseFunctions.js
import * as firebase from 'firebase';
import 'firebase/firestore';
import { Alert, AsyncStorage } from 'react-native';

export async function registration(nickName, email, password, navigation) {
  try {
    console.log(nickName, email, password);
    await firebase.auth().createUserWithEmailAndPassword(email, password);
    const currentUser = firebase.auth().currentUser;
    const db = firebase.firestore();
    db.collection('users').doc(currentUser.uid).set({
      email: currentUser.email,
      nickName: nickName,
    });
    Alert.alert('회원가입 성공!');
    await AsyncStorage.setItem('session', email);
    navigation.push('TabNavigator');
  } catch (err) {
    Alert.alert('무슨 문제가 있는 것 같아요! => ', err.message);
  }
}

export async function signIn(email, password, navigation) {
  try {
    await firebase.auth().signInWithEmailAndPassword(email, password);
    await AsyncStorage.setItem('session', email);
    navigation.push('TabNavigator');
  } catch (err) {
    Alert.alert('로그인에 문제가 있습니다! ', err.message);
  }
}

export async function logout(navigation) {
  try {
    console.log('로그아웃!!');
    const currentUser = firebase.auth().currentUser;
    await AsyncStorage.removeItem('session');
    await firebase.auth().signOut();
    navigation.push('SignInPage');
  } catch (err) {
    Alert.alert('로그 아웃에 문제가 있습니다! ', err.message);
  }
}

export async function addDiary(content) {
  try {
    const db = firebase.firestore();
    let userRef = await db.collection('users').doc(content.uid);

    let data = await userRef.get().then((doc) => {
      return doc.data();
    });
    console.log(data.nickName);
    content.author = data.nickName;
    await db
      .collection('diary')
      .doc(content.date + 'D')
      .set(content);
    return true;
  } catch (err) {
    Alert.alert('글 작성에 문제가 있습니다! ', err.message);
    return false;
  }
}

export async function imageUpload(blob, date) {
  const storageRef = firebase
    .storage()
    .ref()
    .child('diary/' + date);
  const snapshot = await storageRef.put(blob);
  const imageUrl = await snapshot.ref.getDownloadURL();
  blob.close();

  return imageUrl;
}

export async function getData() {
  try {
    const db = firebase.firestore();
    const snapshot = await db.collection('diary').get();
    let data = [];
    snapshot.docs.map((doc) => {
      data.push(doc.data());
    });
    return data;
  } catch (err) {
    console.log(err);
    return false;
  }
}
  1. SignInPage.jsx
import React, { useState, useEffect } from 'react';
import { StyleSheet, ImageBackground, Alert, AsyncStorage } from 'react-native';
import { Container, Content, Text, Form, Button } from 'native-base';
const bImage = require('../assets/background.png');
import ItemInput from '../components/ItemInput';
import { signIn } from '../config/firebaseFunctions';
import * as firebase from 'firebase';
import Loading from '../pages/Loading';
export default function SignInPage({ navigation }) {
  const [ready, setReady] = useState(false);

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const [emailError, setEmailError] = useState('');
  const [passwordError, setPasswordError] = useState('');

  useEffect(() => {
    navigation.addListener('beforeRemove', (e) => {
      e.preventDefault();
    });

    setTimeout(() => {
      AsyncStorage.getItem('session', (err, result) => {
        console.log('ASYNCSTORAGE');
        console.log(result);
        if (result) {
          navigation.push('TabNavigator');
        } else {
          setReady(true);
        }
      });
      setReady(true);
    }, 1000);
  }, []);

  const doSignIn = () => {
    //Email 로그인 버튼을 누를 때 실행되는 함수
    if (email == '') {
      setEmailError('이메일을 입력해주세요');
      return false;
    } else {
      setEmailError('');
    }

    if (password == '') {
      setPasswordError('비밀번호를 입력해주세요');
      return false;
    } else {
      setPasswordError('');
    }

    signIn(email, password, navigation);
  };
  const setEmailFunc = (itemInputEmail) => {
    //이메일 상태값을 관리하는 함수
    setEmail(itemInputEmail);
  };
  const setPasswordFunc = (itemInputPassword) => {
    //패스워드 상태값을 관리하는 함수
    setPassword(itemInputPassword);
  };

  const goSignUp = () => {
    navigation.navigate('SignUpPage');
  };

  return ready ? (
    <Container style={styles.container}>
      <ImageBackground source={bImage} style={styles.backgroundImage}>
        <Content contentContainerStyle={styles.content} scrollEnabled={false}>
          <Text style={styles.title}>
            <Text style={styles.highlite}>we</Text>gram
          </Text>
          <Form style={styles.form}>
            <ItemInput
              title={'이메일'}
              type={'email'}
              setFunc={setEmailFunc}
              error={emailError}
            />
            <ItemInput
              title={'비밀번호'}
              type={'password'}
              setFunc={setPasswordFunc}
              error={passwordError}
            />
          </Form>
          {/* <Button full style={styles.snsSignUp}>
            <Text>Facebook 로그인</Text>
          </Button> */}
          <Button full style={styles.emailSignIn} onPress={doSignIn}>
            <Text>Email 로그인</Text>
          </Button>
          <Button full style={styles.emailSignUp} onPress={goSignUp}>
            <Text style={{ color: '#333' }}>회원가입</Text>
          </Button>
        </Content>
      </ImageBackground>
    </Container>
  ) : (
    <Loading />
  );
}

const styles = StyleSheet.create({
  container: {},
  backgroundImage: {
    width: '100%',
    height: '100%',
  },
  content: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(52, 52, 52, 0.5)',
    margin: 20,
    borderRadius: 20,
  },
  title: {
    fontSize: 25,
    fontWeight: '700',
    color: '#fff',
    textAlign: 'center',
  },
  highlite: {
    fontSize: 25,
    fontWeight: '700',
    color: '#9bf6ff',
    textAlign: 'center',
  },
  form: {
    width: 250,
    borderRadius: 10,
    paddingBottom: 20,
    paddingRight: 20,
    paddingLeft: 20,
    marginTop: 10,
  },
  label: {
    color: '#fff',
  },
  input: {
    color: '#fff',
  },
  snsSignUp: {
    alignSelf: 'center',
    width: 250,
    marginTop: 10,
    borderRadius: 10,
    backgroundColor: '#4667A5',
  },
  emailSignIn: {
    alignSelf: 'center',
    width: 250,
    marginTop: 5,
    borderRadius: 10,
    backgroundColor: '#333',
  },
  emailSignUp: {
    alignSelf: 'center',
    width: 250,
    marginTop: 5,
    borderRadius: 10,
    backgroundColor: '#eee',
    borderWidth: 1,
    borderColor: '#333',
  },
});
profile
코딩초보의 코딩적응기 Coding adaptor for beginners

0개의 댓글