rhanziy

React Native - AsyncStorage, Alert 본문

React Native

React Native - AsyncStorage, Alert

rhanziy 2023. 10. 10. 14:16

AsyncStorage

만들던 어플을 껐다 켜도 데이터가 저장이 되는 storage를 구성해보자!
react native에서 제공하는 AsyncStorage를 프로젝트에 설치해 사용하면 된다.
import도 잊지맙시다.

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

import AsyncStorage from '@react-native-async-storage/async-storage';

 

저장하기(set)

saveToDos -> AsyncStorage.setItem(데이터) 비동기 함수로 처리한다. JSON형식으로 저장해야함~

 const addToDo = async() => {
    if(text === '') { return }
    const newToDos = {...toDos, [Date.now()] : {text, work:working}}

    setToDos(newToDos);
    await saveToDos(newToDos);
    setText("");
  }


const saveToDos = async(toSave) => {
    await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(toSave))
  }

 

가져오기(get)

JSON데이터를 parse해서 getItem으로 꺼낸다.

  const loadToDos = async() => {
    const s = await AsyncStorage.getItem(STORAGE_KEY);
    s !== null ? setToDos(JSON.parse(s)) : null;
  }

 
loadToDos 함수는 useEffect 훅을 사용해 접속시에 실행되는데, 그때 스토리지에 데이터가 저장되어있지 않으면
Cannot convert null value to object
에러가 발생한다. 그러니 데이터가 있는지 없는 지 조건을 검사하고 뿌려줄 데이터를 set한다.
 
그리고 get, set 모두 try catch문을 사용하는게 안전함,,,
 
 
https://react-native-async-storage.github.io/async-storage/docs/usage/

Usage | Async Storage

Async Storage can only store string data. In order to store object data,

react-native-async-storage.github.io

 


Alert

delete 기능을 추가해보자~ 일단 delete 버튼 ui를 만들어주고, onPress하면 deletToDo에 key값이 파라미터로 넘겨져 실행된다. 여기서 key값은 toDos object의 key만 뽑아다가 map 돌린 것.

 <ScrollView>
      {
        Object.keys(toDos).map(key => 
        toDos[key].work === working ? 
          (
            <View key={key} style={styles.toDo}>
              <Text style={styles.toDoText}>{toDos[key].text}</Text>
              <TouchableOpacity onPress={()=>{deleteToDo(key)}} activeOpacity={0.5}>
                <Fontisto name="trash" size={15} color={theme.grey} />
              </TouchableOpacity>
            </View> 
          )
          : null
      )}
  </ScrollView>

 
Alert api를 사용해서 confirm 창을 구현했다.
Alert api는 객체 배열 타입의 alertButton도 제공하는데, text 속성으로 버튼라벨을 달고 onPress 속성으로 버튼 클릭시 콜백함수를 작성한다. iOS에서는 style : 'destructive' 로 버튼 스타일도 줄 수 있음.

const deleteToDo = async(key) => {
    Alert.alert(
      "Delete To Do?", 
      "Are you sure?", [
      { text : "Cancel" },
      { 
        text : "I'm Sure", 
        onPress : () => {
          const newToDos = {...toDos};
          delete newToDos[key];
          setToDos(newToDos);
          saveToDos(newToDos);
        }
      },
      // iOS에서만 적용
      style : 'destructive'
    ])
  }

 
 
🔽 전체코드

더보기
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, TouchableOpacity, TextInput, ScrollView, Alert } from 'react-native';
import { theme } from './colors';
import { useEffect, useState } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Fontisto } from '@expo/vector-icons';

const STORAGE_KEY = "@toDos"


export default function App() {

  const [working, setWorking] = useState(true);
  const [text, setText] = useState("");
  const [toDos, setToDos] = useState({});

  const travel = () => setWorking(false);
  const work = () => setWorking(true);
  const onChangeText = (payload) => setText(payload);

  const saveToDos = async(toSave) => {
    await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(toSave))
  }

  const loadToDos = async() => {
    const s = await AsyncStorage.getItem(STORAGE_KEY);
    s !== null ? setToDos(JSON.parse(s)) : null;
  }

  useEffect(() => {
    loadToDos();
  }, []);

  const addToDo = async() => {
    if(text === '') { return }
    const newToDos = {...toDos, [Date.now()] : {text, work:working}}

    setToDos(newToDos);
    await saveToDos(newToDos);
    setText("");
  }


  const deleteToDo = async(key) => {
    Alert.alert(
      "Delete To Do?", 
      "Are you sure?", [
      { text : "Cancel" },
      { 
        text : "I'm Sure", 
        onPress : () => {
          const newToDos = {...toDos};
          delete newToDos[key];
          setToDos(newToDos);
          saveToDos(newToDos);
        },
        style : 'destructive'
      },
    ])
  }

  return (
    <View style={styles.container}>
      <StatusBar style="auto" />
      <View style={styles.header}>
        <TouchableOpacity activeOpacity={0.5} onPress={work}>
          <Text style={{...styles.btnText, color: working ? "white" : theme.gray}}>Work</Text>
        </TouchableOpacity>
        <TouchableOpacity activeOpacity={0.5} onPress={travel}>
          <Text style={{...styles.btnText, color : !working ? "white" : theme.gray}}>Travel</Text>
        </TouchableOpacity>
      </View>
      <View>
        <TextInput 
          onSubmitEditing={addToDo}
          placeholder={working ? "Add a To Do" : "Where do you want to go?"} 
          value={text}
          style={styles.input}
          keyboardType='email-address'
          returnKeyType='done'
          onChangeText={onChangeText}
        />
      </View>
      <ScrollView>
      {
        Object.keys(toDos).map(key => 
        toDos[key].work === working ? 
          (
            <View key={key} style={styles.toDo}>
              <Text style={styles.toDoText}>{toDos[key].text}</Text>
              <TouchableOpacity onPress={()=>{deleteToDo(key)}} activeOpacity={0.5}>
                <Fontisto name="trash" size={15} color={theme.grey} />
              </TouchableOpacity>
            </View> 
          )
          : null
      )}
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: theme.bg,
    paddingHorizontal: 20,
  },
  header : {
    justifyContent: "space-between",
    flexDirection : "row",
    marginTop: 100,
  },
  btnText : {
    fontSize: 38,
    fontWeight: "500",
  },
  input : {
    backgroundColor: "white",
    paddingVertical: 15,
    paddingHorizontal: 20,
    borderRadius: 30,
    marginVertical: 20,
    fontSize : 18
  },
  toDo: {
    flexDirection: "row",
    justifyContent : "space-between",
    alignItems : "center",
    marginBottom : 10,
    paddingVertical : 20,
    paddingHorizontal : 20,
    backgroundColor : theme.toDoBg,
    borderRadius: 15,
  },
  toDoText : {
    color:"white",
    fontSize : 16,
    fontWeight: "500"
  }
});

 
 
https://reactnative.dev/docs/next/alert#alertbutton

Alert · React Native

Launches an alert dialog with the specified title and message.

reactnative.dev

 

Comments