본문 바로가기
Application/React Native

[React Native 101] #6. Persist&Delete

by junnykim 2022. 7. 25.

~3.8까지의 강의
얼레벌레 전부 듣기는 했지만, 뭔가 휘몰아 쳐서 들은거라 나중에 한 번 더 듣도록 하자

 

 

이제 작은 박스를 수정해보도록 하자.
즉, Work는 Work만 Travel은 Travel만.
work 대신에 working이라고 해서 비교를 해주면 된다.
즉 ScrollView에서 해주면된다.

<ScrollView>
      {Object.keys(toDos).map((key) =>
          toDos[key].working === working ? (
            <View style={styles.toDo} key={key}>
              <Text style={styles.toDoText}>{toDos[key].text}</Text>
            </View>
          ) : null
        )}
      </ScrollView>

todo가 지금 우리가 있는 모드인 working하고 같은지 확인을 해주면 된다.
일치파면, 보여주고 아니면 안 보여주면 된다.


이제 이 메모를 핸드폰에 저장을 해주어야 한다.
expo로 돌아가서, asyncStorage를 사용한다.

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

expo install은 npm install과 동일하지만, expo 버전과 같은 버전의 module을 설치해준다.
그리고 import를 해주면 된다.

saveToDos라는 함수를 만든다.

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

이것은 todo를 String으로 바꿔주고(stringify), toSave의 형태의 saveToDos를 한다.AsyncStorage.setItem을 해준다.toSave는 AddTodo 를 통해 saveToDos에 전해준다.그래서 todo를 item으로 분리해준다.그러면 확실하게 string을 할 수도 있다.await를 해주면 async를 해주면 된다.

새롭게 loadToDos를 만든다.

const loadToDos = async () => {
    const s = await AsyncStorage.getItem(STORAGE_KEY);
    setToDos(JSON.parse(s));
    console.log(JSON.parse(s));
  };


이것도 async를 해준다. 보다시피 local storage라는 것과 비슷하다.getItem은 string을 줄 것이다. 그래서 JS로 하기 위해서 Json.parse해준다.parse는 string을 JS로 만들어주는 것이다.

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

null어쩌고 오류가 난다.. 그럼 이렇게 밑에를 바꿔주면 됩니다~

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

그리고 useEffect는 component가 mount가 될 때 해준다.이 function을 실행시키고 싶으니까 로드 될 때 useeffect를 실행하는 것이다.

 



이제 지우는 것을 해보도록 하자.

toDo를 지우는 버튼을 만들 것이다.
flexDirection을 row로 바꿔주어서 요소들이 가능한 양쪽에 배열되도록 하자.

<TouchableOpacity onPress={() => deleteToDo(key)}>
   <Fontisto name="trash" size={18} color={theme.grey} />
</TouchableOpacity>

TouchableOpacity로 감싼다.

deleteToDo라는 함수를 만든다.

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

그리고 toDo의 id를 받는다.
이것을 만들기 위해서는 onPress를 작성한다.
익명의 function () 을 만들고 이것은 id와 함께 호출한다.
key가 없는 newToDos object를 만든다.

const newToDos를 한다.
async를 해준다. key를 삭제한다.
그래서 state의 내용으로 바꿔주는 것이다.newToDos안에 있는 것을 바꿔주는 것이다. 그 후 state를 업데이트 시키고 asyncStorage에 저장을 하는 것이다.

alertAPI는 대화창을 실행시킨다. 하나는 alert이고 prompt도 있다.근데 prompt는 ios에서만 작동한다. ok만 나오는 대신에 취소 혹은 확인이 작동하도록 만들어보자.

button은 단지 object이다.버튼은 array이다.object가 있는 array가 되는 것이다.onPress는 눌렀을 때 작동하는 것이다. onPress를 누르면 fuction안에 넣어주면 된다.즉, I'm sure을 눌렀을 때 onPress안에 function을 넣어서 기능들이 작동하도록 하면 된다.




최종코드

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

const STORAGE_KEY = "@toDos";

export default function App() {
  const [working, setWorking] = useState(true);
  const [text, setText] = useState("");
  const [toDos, setToDos] = useState({});
  useEffect(() => {
    loadToDos();
  }, []);
  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);
    //setToDos(JSON.parse(s));
    s !== null ? setToDos(JSON.parse(s)) : null;
  };

  const addToDo = async () => {
    if (text === "") {
      return;
    }
    const newToDos = {
      ...toDos,
      [Date.now()]: { text, working },
    };
    setToDos(newToDos);
    //console.log(toDos);
    await saveToDos(newToDos);
    setText("");
  };
  const deleteToDo = (key) => {
    Alert.alert("Delete To Do", "Are you sure?", [
      { text: "Cancel" },
      {
        text: "I'm Sure",
        style: "destructive",
        onPress: () => {
          const newToDos = { ...toDos };
          delete newToDos[key];
          setToDos(newToDos);
          saveToDos(newToDos);
        },
      },
    ]);
  };
  return (
    <View style={styles.container}>
      <StatusBar style="auto" />
      <View style={styles.header}>
      <TouchableOpacity onPress={work}>
          <Text
            style={{ ...styles.btnText, color: working ? "white" : theme.grey }}
          >
            Work
          </Text>
      </TouchableOpacity>
          <TouchableOpacity onPress={travel}>
          <Text
            style={{
              ...styles.btnText,
              color: !working ? "white" : theme.grey,
            }}
          >
            Travel
          </Text>
        </TouchableOpacity>
      </View>
      <TextInput
      onSubmitEditing={addToDo}
        onChangeText={onChangeText}
        returnKeyType="done"
        value={text}
        placeholder={
          working ? "What do you have to do?" : "Where do you want to go?"
        }
        style={styles.input}
      />
      <ScrollView>
      {Object.keys(toDos).map((key) =>
          toDos[key].working === working ? (
            <View style={styles.toDo} key={key}>
              <Text style={styles.toDoText}>{toDos[key].text}</Text>
              <TouchableOpacity onPress={() => deleteToDo(key)}>
                <Fontisto name="trash" size={18} 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: "600",
  },
  input: {
    backgroundColor: "white",
    paddingVertical: 15,
    paddingHorizontal: 20,
    borderRadius: 30,
    marginVertical: 20,
    fontSize: 18,
  },
  toDo: {
    backgroundColor: theme.toDoBg,
    marginBottom: 10,
    paddingVertical: 20,
    paddingHorizontal: 20,
    borderRadius: 15,
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
  },
  toDoText: {
    color: "white",
    fontSize: 16,
    fontWeight: "600",
  },
});

 

colors.js

export const theme = {
    bg: "black",
    grey: "#3A3D40",
    toDoBg: "#5C5C60",
    toDoBg: "#1A1C20",
  };



Code Challenge 언젠가 한다면 코드를 공유하겠소..
1. 내가 어디있는지 기억하기. 즉, Travel에서 끝나면 거기서 시작하기
2. todo function 작성하기. 즉, 아이콘을 추가해서 완료했다는 것을 나타내기
3. 유저가 text를 수정할 수 있도록 하기.

댓글