React Native - 기초2

» FE

해당 내용은 노마드 코더의 React Native 강의를 보고 정리한 내용입니다. https://nomadcoders.co/react-native-for-beginners/lobby

전체 코드

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);
    s !== null ? setToDos(JSON.parse(s)) : null;
  };
  const addToDo = async () => {
    if (text === "") {
      return;
    }
    const newToDos = {
      ...toDos,
      [Date.now()]: { text, working },
    };
    setToDos(newToDos);
    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",
  },
});
  • TextInput 안에 많은 props기 있음

    • keyboardType, returnKeytype, secureTextEntry, multiLine 등 찾아서 하기
  • onChangeText={onChangeText}

    • 내가 쓴 내용으로 함수 실행
  • onSubmitEditing={addToDo}

    • done 누르면 함수 실행
  • const [toDos, setToDos] = useState({});

    • useState([]) 해서 array를 넣어도 되지만 여기선 hashmap 적용
  •   const addToDo = () => {
          if (text === "") {
          return;
          }
          const newToDos = Object.assign({}, toDos, {
          [Date.now()]: { text, work: working },
          });
          setToDos(newToDos);
          setText("");
      };
    
    • state는 언제나 setState로 바꿔야 함 -> 그래서 object에 새로 assign 하는 방식 적용

    • Object.assign({}, toDos, {[Date.now()]: { text, work: working },})

      • 기존 toDos에 {현재시간: text, workstate} 추가
  •   const newToDos = {
          ...toDos,
          [Date.now()]: { text, work: working },
          };
    
    • 이 방식도 가능

    • 이전 object 내용을 가진 새로운 object 만들기

  • Object.keys(x).map(key => x[key])

    • object key 값들에 map 써서 불러오기
  •   {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
              )}
    
    • 현재 work 아니면 안 보이게 하기

✅ AsnyncStorage

- 브라우저의 local storage처럼 작동

- await 필요

- https://react-native-async-storage.github.io/async-storage/docs/usage/ 참고
  • JSON.stringify(toSave)

    • object -> string 변환
  • JSON.parse(s);

    • string -> object 변환
  •   const newToDos = { ...toDos };
      delete newToDos[key];
    
    • 이전 todo 내용 복사해서 이전 내용으로 되돌리고 newtodo 삭제

    • const newToDos = {...toDos} 처럼 새로운 객체 내에 기존 객체의 key-value를 풀어놓는 대신 const newToDos = todo 와 같은 형태로 복사하게 되면 이후 setToDos(newToDos)로 state를 변경할 때 자동으로 re-render가 되지 않음