본문 바로가기
React Native

[RN] 투두 리스트를 만들어보자! (2)

by Meaning_ 2022. 5. 21.
728x90
반응형

Persist

 

 

work와 travel의 투두리스트가 달라야 하는데 지금 똑같이 보인다. 

 

우선 toDo를 저장하는 Object에서 work:working을 그냥 working으로만 바꾼다

여기서 working은 useState변수 였다!

 

내가 만약 work에 해당하는 투두 리스트를 쓴다면

work에 해당하는 Touchable에서 work함수를 호출하고

setWorking이 true가 된다.

work에 해당하는 toDo를 입력해주면

toDo 객체에 현재 working 상태가 들어가는데 

 

toDo의 working 상태와 현재의 working의 상태가 같을때만 View를 띄우고 그게 아니면 null을 반환한다

예를 들어 현재 working이 true이면 work 투두리스트만 보여주는 거고

working이 false이면 travel투두리스트만 보여주는 것이다. 

 

 

 

Async storage

 

앱을 닫고 다시 들어와도 사용자의 toDo를 저장하려고 한다.

 

expo의 async-storage를 이용할 것이다.

브라우저의 local storage 처럼 작동하는데 대신 async await을 해줘야 한다!

 

saveToDos함수는 현재 toDos를 String으로 바꿔주고 await AsyncStorage.setItem을 해줄 것이다. 

saveToDos 함수는 toSave 형태의 toDos를 받을 것인데 toSave는 addTo 함수를 통해

saveToDos에 전해질 것이다. 

 AsyncStorage.setItem()이라 하고 key와 value를 넣어줘야 한다. 

toSave를 stringify를 해서 문자열 형태로 AsyncStorage에 넣어준다. !

 

loadToDos라는 함수를 줬는데 여기서 getItem은 string을 준다. 

parse를 통해 string을 js Object로 만들어준다. 

이걸 setToDos에 넣어주면 앱을 꺼도 내가 쓴 투두가 남아있다.

 

왜 setToDos에 넣어주나 했는데 그래야지 parse된 내용이 toDos 라는 Object에 들어가면서 (useState)

나중에 map을 하며 UI에 투두리스트를 띄울 수 있는거였다! 

결국 UI에 뜨는 객체는 toDos이기에 얘를 수정하는 setToDos가 중요하다!!

 

++) 정리

setToDos를 통해 현재 state 저장 

saveToDos를 통해 이전 toDo를 Async Storage에 저장 

 

delete 

 

이제 todo를 지우는 것을 해볼 것이다. 

 

우선 toDo 텍스트 밑에 x 버튼을 만들어준 후 

onPress 속성을 추가해주는데, x버튼을 누르면 deleteToDo 함수가 실행되고 props로 key를 가져간다. 

 

그럼 이제는 deleteToDo 함수를 보자.

우선 newToDos는 이전의 toDos 객체를 받아오고 --> ...은 Object Assign을 더 쉽게하는 법에서 배웠다.

 

https://we1cometomeanings.tistory.com/405?category=1013957 

 

[RN] 투두 리스트를 만들어보자!(1)

유저가 submit 버튼 누르는걸 감지하도록 만들어볼거다. 이때 사용하는 props가 onSubmitEditing이다. 버튼이 눌렸다면 addToDo 함수가 실행될거고 이때 text가 비어있으면 리턴해주고 그게 아니라면 setText

we1cometomeanings.tistory.com

매개변수로 받아온 id에 해당하는 객체만 newToDos에서 삭제한다. 그리고 그 삭제가 반영된 내용을 setToDos와 saveToDos에 넣어서 반영시켜 준다. 

 

 

결국 state의 내용으로 새로운 object를 만들어주는 것이라 생각하면 된다. 

 

 

Alert API

 

사용자 정말로 todo를 지우고 싶은지 알람창을 띄우기 위해 Alert API를 사용해볼건데 이거는 대화창(팝업창)

을 실행시킨다. 

 

하나는 alert()이고 prompt()가 있다. 

 

버튼은 array인데, Object가 들어있는 array이다. 배열 안에 객체를 쓰는건 Alert의 특징인것 같다. 무조건 써야하는..?!

https://docs.expo.dev/versions/latest/react-native/alert/

 

Alert - Expo Documentation

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.dev

props가 id가 아니라 key여야 한다..!

Alert.alert을 통해 경고창을 띄우고

만약 sure을 사용자가 클릭하면 아까만들어준 delete newToDos 코드를 "I'm sure" 밑에 넣어준다.

 

 

 

최종코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text,  View,TouchableOpacity,
TextInput,ScrollView, Alert } from 'react-native';
import React, { useEffect, useState } from "react";
import { WebView } from 'react-native-webview';
import { theme } from './colors';
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);
  useEffect(()=>{
    loadToDos();
  },[]);
 
  const saveToDos=async (toSave)=>{
    const s=JSON.stringify(toSave);
    await AsyncStorage.setItem("@toDos",s);
 
  }
 
  const loadToDos=async()=>{
    const s= await AsyncStorage.getItem(STORAGE_KEY);
    setToDos(JSON.parse(s));
  };
  
  const addToDo=async()=>{
    if(text===""){
      return;
    }
 
    const newToDos={...toDos,[Date.now()]:{text,working}}
 
    setToDos(newToDos);
    await saveToDos(newToDos);
    //save to do
    setText(text);
  }
 
  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>
      <View>
        <TextInput 
        onSubmitEditing={addToDo}
        onChangeText={onChangeText}
        returnKeyType='done'
        placeholder={working?"Add a To Do":"Where do you want to go?"}
        style={styles.input}/>
        <ScrollView>
          {Object.keys(toDos).map((key)=>
          toDos[key].working===working?(
          <View key={key} style={styles.toDo}>
            <Text style={styles.toDoText}>{working? "📝"+toDos[key].text:"📸"+toDos[key].text}</Text>
            <TouchableOpacity onPress={()=>deleteToDo(key)}>
              <Fontisto name="trash" size={18} color={theme.grey} />
            </TouchableOpacity>
            </View>):null)}
        </ScrollView>
      </View>
 
     
      
    </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:{
    marginBottom:10,
    flexDirection:"row",
    paddingVertical:20,
    paddingHorizontal:40,
    backgroundColor:theme.toDoBg,
    borderRadius:15,
    alignItems:"center",
    justifyContent:"space-between",
 
 
  },
  toDoText:{
    color:"white",
    fontSize:16,
    fontWeight:"500",
 
 
  },
});
 
 
cs

 

 

++) useEffect의 역할

 

어플리케이션이 재실행되면 loadToDos를 호출 시켜서 이전에 Async Storage에 저장된 애들을 투두 리스트에 띄워준다. 

728x90
반응형

'React Native' 카테고리의 다른 글

[RN] 투두리스트 코드챌린지  (0) 2022.05.21
[RN] 투두 리스트를 만들어보자!(1)  (0) 2022.05.21
[RN] TextInput  (0) 2022.05.21
[RN] TODO APP - 헤더 만들기  (0) 2022.05.20
[RN] WeatherApp 만들기 - Icons 사용하기  (0) 2022.05.14

댓글