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

  

앱을 완전히 껐다가 켰을 때, 다시 로그인해야 하면 참 귀찮아진다. 사용자들의 편의를 위해서 요즘 앱들은 껐다가 다시 켜도 로그인되어 있는 화면을 다시 보여주곤 한다.

그렇게 할 수 있는 것은, 앱이 꺼지기 직전에 사용자가 로그인이 되어 있었는지 체크 한 후, 로그인한 적이 있으면(아직 로그아웃하지 않았다면) 바로 메인 화면으로 보내는 로직을 사용하기 때문이다. 

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

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

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

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

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

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

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

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

2. AsyncStorage 사용하기.

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

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

순서로 살펴보자면, 

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

 2) useEffect에서 AsyncStoragesession 통을 살펴본다 

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

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

간단하쥬~? :)

3. 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;
}
}

4. 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',
},
});

댓글

이 블로그의 인기 게시물

[R studio] pkg 설치 오류시 대처법

[Apple Developer 조치 필요: Distribution 인증서가 30일 후에 만료됨] 메일이 왔을때 대처법

[Unable to find bundled Java version =>Mac Flutter Android Studio Arctic Fox 2020.3.1] flutter doctor -v 실행시 안드로이드 스튜디오 오류 메시지 해결