[React-Native]To-Do-App 저장하기


지금까지 따라 오시느라 수고하셨습니다. 이제 잘 작동되는 앱의 형태를 가지고 있는데요, 하지만 reload할 경우 작업한 내용을 기억하지 못하는 단점이 존재합니다.

오늘은 작업한 내용을 휴대폰 자체 저장소에 저장하고 불러올 수 있게 하는 작업을 해봅시다.


AsyncStorage

리액트 네이티브에서 제공하는 AsyncStorage 모듈은 Key-Value형태로 데이터를 저장하고, 이는 앱 어디에서나 접근이 가능합니다.
이는 웹을 사용할 때 로컬 저장소를 사용하는 것과 동일합니다.

To-Do-App에 저장해야 하는 데이터는 어떤 것이 있는지 알아보겠습니다.

  1. 할 일 목록

  2. 각 할 일의 완료여부

등 할 일에 관련된 정보입니다. 이러한 것들은 현재 state.todos에 저장되고 있습니다.
즉, 우리가 저장해야 할 데이터는 state의 todos값이니 이걸 저장하면 됩니다.


데이터를 저장하는 함수 만들기

//App.js

import React from 'react'
import { StyleSheet, Text, View, FlatList,AsyncStorage } from 'react-native'
import Header from './app/components/Header'
import SubTitle from './app/components/SubTitle'
import Input from './app/components/Input'
import TodoItem from './app/components/Todo'

export default class App extends React.Component {

  state = {
    inputValue: "",
    todos: [
      {
        title: "물 3잔 마시기",
        isComplete: false
      },
      {
        title: "30분 이상 걷기",
        isComplete: false
      }
    ]
  }

  saveItem = () => {
    //state를 문자열로 바꿔서 저장함
    AsyncStorage.setItem('@todo:state',JSON.stringify(this.state))
  }
....

먼저 react-native에서 AsyncStorage를 import 해줍니다.
그리고 saveItem 이라는 함수를 만들어줍니다.
AsyncStorage.setItem(‘@todo:state’,JSON.stringify(this.state))
AsyncStorage 모듈의 setItem 메소드는 AsyncStorage.setItem(key: string,value: string)의 형식을 따릅니다. 그리고 key는 보통 @앱이름: 키 이름으로 작성하는 것이 일반적입니다.
JSON.stringify()는 괄호안에 있는 내용을 JSON형태의 문자열로 변경해주는 열할을 합니다.

이제 state가 변경 될때마다 saveItem을 호출하면 자체 저장소에 데이터가 저장될 것입니다.


만든 함수 호출하기

우리는 할 일의 완료 여부를 변경할 때, 할 일을 추가 할 때, 할 일을 삭제할 때 처럼 state가 변경되면 데이터를 저장해야합니다.
우리는 이러한 작업을 위해 this.setState 작업이 끝나면 saveItem함수를 사용할 예정입니다. setState 메서드의 두번째 인자에 callback함수를 작성하면 됩니다.

//App.js

_makeTodoItem = ({ item, index }) => {
    return (
      <TodoItem
        text={item.title}
        isComplete={item.isComplete}
        changeComplete={() => {
          const newTodo = [...this.state.todos];
          newTodo[index].isComplete = !newTodo[index].isComplete;
          this.setState({todos:newTodo},this.saveItem);
        }}
        deleteItem={() => {
          const newTodo = [...this.state.todos];
          newTodo.splice(index,1);
          this.setState({todos:newTodo},this.saveItem)
        }} />
    )
  }

  _changeText = (value) => {
    this.setState({inputValue:value})
  }

  _addTodoItem = () => {
    if(this.state.inputValue !== ''){
      const Input = this.state.inputValue;
      const prevItem = this.state.todos;
      const newItem = { title: Input, isComplete: false}
      this.setState({
        inputValue: '',
        todos: prevItem.concat(newItem)
      },this.saveItem)
    }
  }

첫째로, 완료여부가 변경될 때
둘때로, 할 일을 삭제한 뒤
셋째로, 할 일을 추가한 뒤
각각의 setState의 callback함수로 saveItem함수를 넣어줍니다. state설정이 끝난 뒤 saveItem 함수가 실행 됩니다.


앱이 로딩될 시 데이터 가져오기

현재 데이터가 변결될 때, 자체 저장소에 데이터를 저장하고 있습니다.
이제는 앱이 로딩될 때 저장된 데이터를 가져와서 보여주는 기능을 추가해봅시다.

// App.js

export default class App extends React.Component {

  state = {
    inputValue: "",
    todos: [
      {
        title: "물 3잔 마시기",
        isComplete: false
      },
      {
        title: "30분 이상 걷기",
        isComplete: false
      }
    ]
  }

  componentWillMount() {
    AsyncStorage.getItem('@todo:state').then((state)=> {
        if( state != null){
            this.setState(JSON.parse(state));
        }
    });
  }

  saveItem = () => {
    //state를 문자열로 바꿔서 저장함
    AsyncStorage.setItem('@todo:state',JSON.stringify(this.state));
  }

....

componentWillMount 라는 함수를 추가해줍니다.
이 함수는 React의 라이프사이클 함수중 하나입니다. 라이프 사이클함수는 컴포넌트가 생성되기 전 후 및 데이터가 변경되어, 상태를 업데이트하기 전 후로 실행되는 함수입니다.

즉, 자동으로 React에서 생성해주는 함수이고, 그 중 componentWillMount는 컴포넌트가 모두 생성 된 후에 바로 실행됩니다. 이 함수안에서 데이터를 불러올 예정입니다.

AsyncStorage.getItem(key) 메소드를 써서 데이터를 가져옵니다. 가져온 후 데이터를 앱에 반영해줘야 하는데 .then 키워드를 사용해 promise를 구현해 보겠습니다.
promise는 위에서 사용한 callback함수와 비슷한 개념입니다. JSON.parse() 메서드는 아까 그 JSON 문자열의 구문을 분석해서 JavaScript 값이나 객체를 생성합니다.

이제 결과를 확인해 보겠습니다.