FrontEnd :-)

[RN] study 5week / 할일 목록 만들기 ②-② 본문

React Native

[RN] study 5week / 할일 목록 만들기 ②-②

code10 2023. 3. 13. 00:39

React Navtive 스터디 5week

도서: [리액트 네이티브를 다루는 기술 / 김민준 / 길벗]

(4장 할일 목록 만들기 ②-②)

 

4.1 불변성을 지키면서 객체와 배열 업데이트하기

4.2 todos 상태 만들기 및 FlatList로 항목 화면에 나타내기

4.3 새 항목 등록하기

4.4 할일 완료 상태 토글하기

4.5 항목 삭제하기

4.6 AsyncStorage로 앱이 꺼져도 데이터 유지하기

4.7 정리


4.3 새 항목 등록하기 

onInsert 함수 구현 => //새로 등록할 항목의 id 구하기, 등록된 항목 중에서 가장 큰 id를 구하고 + 1, 리스트 비었으면 1을 id로

//App.tsx

const onInsert = (text: string) => {
    const nextId =
      todos.length > 0 ? Math.max(...todos.map(todo => todo.id)) + 1 : 1;
    const todo = {
      id: nextId,
      text,
      done: false,
    };

    setTodos(todos.concat(todo));
  };
    
  retrun( 
  (...)
  <AddTodo onInsert={onInsert} />
  (...)

AddTodo 컴포넌트에서 oninsert 함수 props로 받아와서 onPress 함수에서 현재 text 상태를 인자로 넣어 호출

//AddTodo.tsx

const onPress = () => {
    onInsert(text);
    setText('');
    Keyboard.dismiss();
  };

 

(Typescript) 함수 props로 넘기고 자식 컴포넌트에서 타입 설정.

//AddTodo.tsx

type Props = {
  onInsert: (text: string) => void;
};

function AddTodo({onInsert}: Props) {

4.4 할일 완료 상태 토글하기

토글(Toggle)이란 하나의 값을 다른 값으로 전환하는 것.

App 컴포넌트에 onToggle 함수 작성하고, 해당 함수를 TodoList의 Props로 설정, 고유 값 id를 파라미터로 받아온다.

//App.tsx

const onToggle = (id: number) => {
    const nextTodos = todos.map(todo =>
      todo.id === id ? {...todo, done: !todo.done} : todo,
    );
    setTodos(nextTodos);
  };
  
  (...)
  <TodoList todos={todos} onToggle={onToggle} />
  (...)
//TodoList.tsx

type TodosProps = {
  todos: TodosType[];
  onToggle: (id: number) => void;
};

function TodoList({todos, onToggle}: TodosProps) {
  return (
    (...)
      renderItem={({item}) => (
        <TodoItem
          id={item.id}
          text={item.text}
          done={item.done}
          onToggle={onToggle}
        />
    (...)

TodoItem 컴포넌트에서 onToggle 사용하기 . TouchableOpacity 컴포넌트로 감싼 후 onPress로 터치

//TodoItem.tsx

function TodoItem({id, text, done, onToggle}: TodosProps) {
  return (
    <View style={styles.item}>
      <TouchableOpacity onPress={() => onToggle(id)}>
        <View style={[styles.circle, done && styles.filled]}>
          {done && (
            <Image
              source={require('../assets/icons/check_white/check_white.png')}
            />
          )}
        </View>
      </TouchableOpacity>
      <Text style={[styles.text, done && styles.lineThrough]}>{text}</Text>
    </View>
  );
}

<TouchableOpacity onPress={() => onToggle(id)}>

함수를 만들어 특정 상수 또는 변수에 담지 않고 바로 사용하는 함수를 익명 함수라고 함. 함수가 간결하고, 사용하는 곳이 한 곳밖에 없다면 익명 함수 작성해도~

!!주의!!  onPress={onToggle(id)} 와 같이 코드 작성하면 안 된다!! 이러면 컴포넌트가 렌더링될 때마다 onToggle이 호출되는 상황이 발생. onToggle이 호출되면 컴포넌트는 또 리렌더링되고, 결국 앱에서 오류 발생함.


4.5 항목 삭제하기

4.5.1 벡터 아이콘 사용하기

react-native-vector-icons 라이브러리 사용

yarn add react-native-vector-icons

iOS와 안드로이드 프로젝트에 적용하려면,

4.5.1.1 iOS에 react-native-vector-icons 적용

cd ios
pod install

그 다음, ios/TodoApp/Info.plist 파일에서 맨 마지막 </dict> 전에 아래와 같이 코드 입력. 

plist 파일은 iOS 앱의 프로퍼티 리스트(property list) 파일로 앱의 이름, 아이콘, 버전 등 앱에서 필요한 설정값을 지닌다.

여기에 추가할 폰트로 어떤 있는지는 node_modules/react-native-vector-icons/Fonts 디렉터리를 열어보거나 아래 링크에서 확인

https://github.com/oblador/react-native-vector-icons/tree/master/Fonts

// ios/TodoApp/Info.plist 

<key>UIAppFonts</key>
<array>
	<string>MaterialIcons.ttf</string>
</array>

MaterialIcons는 구글에서 디자인한 폰트-

설치했으면 yarn ios

 

4.5.1.2 안드로이드에 react-native-vector-icons 적용

android/app/build.gradle 파일 맨 아래에 아래 텍스트 추가

apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle")

build.gradle 파일은 안드로이드의 범용 빌드 도구인 Gradle에서 사용하는 파일. 프로젝트의 의존성, 플러그인 및 빌드에 필요한 설정에 대한 정보를 지님. 

설치 끝나면 yarn android

 

4.5.1.3. 삭제 아이콘 보여주기

https://oblador.github.io/react-native-vector-icons/에서 아이콘 검색

아이콘 name 확인해서 사용하기

import Icon from 'react-native-vector-icons/MaterialIcons';
const deleteIcon = <Icon name="delete" size={32} color="red" />;

4.5.2 항목 삭제 함수 만들기

 //App.tsx 
 
 const onRemove = (id: number) => {
    const nextTodos = todos.filter(todo => todo.id !== id);
    setTodos(nextTodos);
  };

onToggle 함수 만들고 적용하는 것과 비슷

App 컴포넌트에 onRemove 함수 작성하고, 해당 함수를 TodoList의 Props로 설정, 고유 값 id를 파라미터로 받아온다. TodoItem 컴포넌트에서 onRemove 사용하기 . TouchableOpacity 컴포넌트로 감싼 후 onPress로 터치

<TouchableOpacity onPress={() => onRemove(id)}>
	<Icon name="delete" size={32} color="red" />
</TouchableOpacity>

 

삭제 잘 됨~

 

4.5.3 항목을 삭제하기 전에 한번 물어보기

//TodoItem.tsx
import {
  Alert,
  Image,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

// 삭제 전 한번 물어보기
  const remove = () => {
    Alert.alert(
      '삭제',
      '정말로 삭제하시겠어요?',
      [
        {text: '취소', onPress: () => {}, style: 'cancel'},
        {
          text: '삭제',
          onPress: () => {
            onRemove(id);
          },
          style: 'destructive',
        },
      ],
      {
        cancelable: true,
        onDismiss: () => {},
      },
    );
  };
  
  (...)
  {done ? (
        <TouchableOpacity onPress={remove}>
          <Icon name="delete" size={32} color="red" />
        </TouchableOpacity>
      ) : (
        <View style={styles.removePlaceholder} />
      )}
(...)

Alert.alert 함수의 파라미터는 제목, 내용, 버튼 배열, 옵션 객체 순서입니다.

버튼 배열에 넣는 버튼 객체에는 text 값을 통해 버튼의 이름을 지정할 수 있고, onPress를 통해 버튼을 눌렀을 때 호출할 함수를 설정할 수 있다.

 

style은 cancel, default, destructive 값을 설정할 수 있는데, iOS에서만 작동.

cancel: 취소를 의미하며 폰트가 두껍게 나타남.

default: 기본을 의미, 기본 버튼(파란색 텍스트)가 나타남.

destructive: '파괴적'인 것으 ㄹ의미, 삭제하는 상황 등에 적합한 스타일

 

안드로이드의 경우, 버튼 스타일 변경을 원하면 컴포넌트를 직접 제작해야 함.

Comments