본문 바로가기

[내일배움캠프]/TIL

22.12.30) React native(add,edit,delete,api)를 배운 45일차

#오늘 배운것

★리액트네이티브 공식문서에서 단어 한번 쳐보기!!!

 

expo 화면 새로고침하기 = 터미널 expo start후 밑의 명령어 모음에 "Press r"이 있다. 그럼 터미널을 활성화 한 상태에서 R을 누르면 새로고침이 된다.

 

웹의 경우 마우스로 누르는것을 고려해야하는데 앱의 경우 완료 , enter버튼누르면 적용되기 때문에 그것만 고려하면 된다. 그것이 onSubmitEditing입니다.

 

리액트 네이티브는 html의 div같은 기본적인 태그를 가져오는데도 import를 해야한다.또한 기본적으로 flexbox가 디폴트 값이다!!!!! display:flex 안써도 됨. 그리고 모바일에서는 기본 flex derction이 column형태다.기본이 위 > 아래

 

status bar = 아이폰의 시간이나 wifi상태를 보여주는 태그.안드로이드는 안보임...

SafeAreaView = 폰 위의시간부분이 겹치지 않게 하려고 padding을 인식해 자동으로 주는 것. 그래서 style로 줄 수 없다. 충격...윈도우는 안 보인다고...
 
flex주는 이유 스트레치를 주기 위해 !!flex를 안주면 찌부된다...
 
!!.filter보다는 if문으로 처리하는것이 좀 더 깔끔하다.모든 배열 요소를 순회할때까지 멈추지 않기 때문에 .filter().map으로 처리하면 더 많이 돌아야한다..!!
 
 debug remote js = start~로 시작되는거면 웹 내에서 켜서 시작하면 된다. 시뮬레이터는 커맨드+D인데...윈도우는 몰겟다..
 
json데이터를 깔끔하게 정리해주는 사이트 : https://jsonformatter.curiousconcept.com/#
 

JSON Formatter & Validator

Format and validate JSON data so that it can easily be read by human beings.

jsonformatter.curiousconcept.com

.map을 썼으면 key값을 쓸것..까먹지 말자...

자동완성이 안되어있으면 import가 안되어 있는 것....

yarn add @react-native-async-storage/async-storage

//
import AsyncStorage from '@react-native-async-storage/async-storage';
export default function App() {
  //add Todo : input창에서 enter누르면 todo가 추가된다.
  const [todos, setTodos] = useState([]);
  const [category, setCategory] = useState(""); //js,react,ct 초기값을 주면 리로드 됐을 때 ui적으로 좋지 않아서 빈배열로 쓰는게 좋을것같다...
  const [text, setText] = useState("");
  const [editText, setEditText] = useState("");

  //setCategory : 탭별로 다른 todo 보이기(bg에 삼항연산자 주기)
  //react에서는 filter를 따로 줬지만 여기서는 조건문으로 filter를 한다.
  //style 조건문을 할때는 style={{  ...styles.HeaderButton,backgroundColor: category === "js" ? "#ffff00" : "#ffaa00", }}이런 형식으로 한다.
  //todos와 category별개로 저장해야한다.

  //isDone,완료 토글링
  const setDone = (id) => {
    //id를 매개변수로 받아 -> id의 해당 요소를 찾는다. -> 그 배열 요소 isDone값을 토글링한 후 setTodos한다.
    const newTodos = [...todos];//얕은 복사
    const idx = newTodos.findIndex(todo => todo.id === id);//id에 해당하는 idx찾기.todo에서 매개변수로 받은 id랑 같으면!
    newTodos[idx].isDone = !newTodos[idx].isDone;//찾은 인덱스를 토글링 !
    setTodos(newTodos);
  };
  //코드 치기 전 체계적으로 생각해라....

  const newTodo = {
    id: Date.now(), //현재 시간을 숫자로 표현한 id
    text,
    isDone: false,
    isEdit: false, //수정값
    category, //카테고리 어디에 해당하는지..
  };

  const addTodo = () => {
    setTodos((prev) => [...prev, newTodo]);//기존 todo값에 접근해 뒤에 새로운 todo생성.
    setText("");
  };
  //Delete Todo : 삭제 이모티콘 터치 시 해당 todo 삭제!!alert쓴다.
  const deleteTodo = (id) => {
    //alert.alert(제목,내용,[{취소시 행동},{삭제시 행동}])
    Alert.alert("Todo삭제", "삭제하시겠습니까", [
      {
        text: "취소",
        style: "cancel",
        onPress: () => console.log("취소됨"),
      },
      {
        text: "삭제",
        style: "destreutive",
        onPress: () => {
          //삭제를 눌렀을 때 나오는 행동.
          //1. id값을 받아서 해당 배열 요소를 제외한 나머지르 새로운 배열로 받는다.
          //2. setTodos
          //얕은 복사대신 왜 직접 todo를 지정하는가.
          //filter는 immutable메소드라서 todos에 영향을 미치지 못한다..
          const newTodos = todos.filter((todo) => todo.id !== id);
          setTodos(newTodos);
        },
      },
    ]);
  };
  //edit : 수정을 누르면 input창이 뜸.
  const isEdit = (id) => {
    const newTodos = [...todos];
    const idx = newTodos.findIndex((todo) => todo.id === id);
    newTodos[idx].isDone = !newTodos[idx].isDone;
    setTodos(newTodos);
  };
  const editTodo = (id) => {
    //1.id값을 받아서 해당 배열의 요소[idx]를 찾음.
    //2. todos[idx].text = editText; (얕은복사)
    const newTodos = [...todos];
    const idx = newTodos.findIndex((todo) => todo.id === id);
    newTodos[idx].text = editText;
    //수정을 마친다음 isEdit창을 닫아줘야 한다.
    newTodos[idx].isEdit = false;
    setTodos(newTodos);

  };
  //컴포넌트가 마운트 됐을 때 로컬 스트리지 대신 에이씽크 스토리지를 사용하여 데이터 유지 async 임포트 해야함.
  //대신 비동기로 사용함.(함수안에서만 쓸 수 있는 제약조건이 있다..)
  useEffect(()=> {
    const saveTodo = async() => {
        //todos가 변할때 마다 현재 상태를 저장.
      await AsyncStorage.setItem("todos",JSON.stringify(todos))
    //getData를 하지않아도 얘는 자동으로 읽어준다.todos가 원래는 빈배열이니까..뭘..생성하면...그떄부터 렌더링되게..
    if (todos.length >0) saveTodo();

  }},[todos])

  useEffect(() => {
    const getData = async () => {
      const res = await AsyncStorage.getItem("todos");
      const resCate = await AsyncStorage.getItem("category");
      //파싱한 값을 가지고 setTodos를 한다.최초 렌더링 되자마자 기억한 값을 보여준다.
      setTodos(JSON.parse(res));
    }
    getData();
  },[])


  const setCate = async (cat) => {
    setCategory(cat);
    //얘는 걍 문자열이라 JSON.stringify생략해도 상관없다.
    await AsyncStorage.setItem("category",(cat))
  }
  return (
    <View style={styles.container}>
      <StatusBar style="auto" />
      <SafeAreaView style={styles.headerText}>
        <TouchableOpacity
          style={{
            ...styles.HeaderButton,
            //스타일의 조건문.
            backgroundColor: setCate === "js" ? "#ffff00" : "#ffaa00",
          }}
          onPress={() => "js"}
        >
          <Text>Javascript</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={{
            ...styles.HeaderButton,
            backgroundColor: setCate === "react" ? "#ffff00" : "#ffaa00",
          }}
          onPress={() => "react"}
        >
          <Text>react</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={{
            ...styles.HeaderButton,
            backgroundColor: setCate === "ch" ? "#ffff00" : "#ffaa00",
          }}
          onPress={() => "ch"}
        >
          <Text>ch</Text>
        </TouchableOpacity>
      </SafeAreaView>
      <TextInput
        style={styles.TextInput}
        placeholder="아무거나 입력해주세요."
        onSubmitEditing={addTodo}
        onChangeText={setText} //함수가 들어가면 되는데 setText가 함수라 그냥 넣어도 상관X.공식홈페이지에 Textinput페이지에 대놓고 나온다.참고...
        value={text}
      />
      {todos.map((todo) => {
        //이중포문을 쓴것이다.조건문을 주기위해 {}로 감싸기.
        if (category === todo.category) {//카테고리가 todo의 카테고리와 같으면 리턴하기
          return (
            <View key={todo.id} style={styles.bodyContainer}>
              {todo.isEdit ? (
                <TextInput
                  style={styles.TextInput}
                  placeholder="아무거나 입력해주세요."
                  onSubmitEditing={() => editTodo(todo.id)}
                  onChangeText={setEditText} //함수가 들어가면 되는데 setText가 함수라 그냥 넣어도 상관X.공식홈페이지에 Textinput페이지에 대놓고 나온다.참고...
                  value={edittext}
                />
              ) : (
                <Text
                  style={{
                    ...styles.Todo,
                    textDecorationColor: todo.isDone ? "line-threough" : "none",
                  }}
                >
                  {todo.text}
                </Text>
              )}
              <Text
                style={{
                  ...styles.Todo,
                  textDecorationLine: todo.isDone ? "line-threough" : "none",
                }}
              >
                {todo.text}
              </Text>
              <TouchableOpacity>
                <AntDesign
                  name="edit"
                  size={24}
                  color="black"
                  onPress={() => setDone(todo.id)}
                />
              </TouchableOpacity>
              <TouchableOpacity onPress={() => setEdit(todo.id)}>
                <AntDesign name="checkcircleo" size={24} color="black" />
              </TouchableOpacity>
              <TouchableOpacity>
                <AntDesign
                  name="delete"
                  size={24}
                  color="black"
                  onPress={() => deleteTodo(todo.id)}
                />
              </TouchableOpacity>
            </View>
          );
        }
      })}
    </View>
  );
}

 

#과제

에이씽크 스토리지 다 빼고

몽고db면 firestore 로그인 안해도 등록이 가능하다고 함...json서버 사용해도 무관함.

프로젝트 만들고 ios랑 and말고 web으로 무조건 선택하기!!!

파이어베이스 스니펫 그대로 써도디는데 cdn이 아니라 npm firebase다운받기 때문에 프로젝트 셋업때 프로젝트 설정 ->npm install firebase옮겨서 사요ㅕㅇ한다.