[TIL] 22.08.24 WED

seongminn·2022년 8월 24일
0

TIL

목록 보기
8/11
post-thumbnail

불변성(Immutability)

불변성이란?

리액트에서 객체와 배열 타입의 상태를 다룰 때에는 불변성을 지켜야 한다. 불변성이란, 객체 또는 배열을 직접 수정하지 않는다는 것을 의미한다.

가령 다음과 가은 객체가 있다고 가정해보자.

const data = {
  id: 1,
  name: seongmin,
}

이 때, data.name의 값을 바꾸려 한다면 대표적으로 다음과 같은 코드를 작성할 수 있다.

// 1.
data.name = "react"

// 2.
const newData = {
  ...data, // 스프레드 연산자 사용
  name: "react"
}

위 두 코드 중 첫 번째 방법은 객체의 값을 직접 변경한, 불변성을 지키지 않은 코드이다.

불변성을 지켜야 하는 이유?

그렇다면 불변성을 지켜야 하는 이유는 무엇인가?

리액트는 부모 컴포넌트의가 변경되어 리랜더링(re-randering) 되면 자식 컴포넌트 역시 리랜더링 된다. 중요한 것은 자식 컴포넌트의 상태가 변경되지 않아도 무조건적으로 리랜더링된다는 것이다. 그래서 컴포넌트에서 다루는 데이터의 양이 많아지거나 연산량이 증가하여, 부모 컴포넌트가 리랜더링 될 때마다 모든 자식 컴포넌트가 리랜더링 된다면 성능에 부하가 발생할 것이다. 이 때, 컴포넌트의 Props를 통해 위와 같은 불상사를 방지할 수 있다.

컴포넌트가 이전에 갖고 있던 Props와 새로 받아온 Props를 비교하여 변화가 일어났을 때만 리랜더링하여 리액트의 랜더링 성능을 최적화할 수 있다. 이 과정에서 불변성을 유지하는 것이 중요해진다.

다음과 같은 코드가 있다.

const data = {
  id: 1,
  name: "seongmin",
}

const newData = data
newData.name = "react"

console.log(data === newData); // true

위와 같은 결과가 발생하는 이유는 바로 리액트 객체의 불변성 때문이다. datanewData는 변수명이 다를지라도 불변성을 지키지 않았기 때문에 같은 객체를 가리키고 있다. 그래서 newDataname 속성을 변경하면 data.name의 값도 변경이 되고, 이를 비교했을 때 true가 반환되는 것이다.

불변성을 유지하면서 상태를 업데이트하려면 다음과 같이 코드를 작성할 수 있다.

const data = {
  id: 1,
  name: "seongmin",
}

const newData = {
  ...data,
  name: "react",
}

console.log(data === newData); // false

이제 datanewData는 서로 다른 객체를 가리키고, newData의 값을 변경해도 data의 값은 변경되지 않는다.

배열의 불변성

배열 타입의 상태를 다룰 때에도 불변성을 유지해야 한다. 리액트 배열의 내장 함수를 사용하면 쉽게 상태를 변경할 수 있다.

새로운 항목 추가

// 스프레드 연산자 활용
const arr = [1, 2, 3, 4, 5]
const nextArr = [...arr, 6] // [1, 2, 3, 4, 5, 6]

// Array.concat() 함수 활용
const arr = [1, 2, 3, 4, 5]
const nextArr = arr.concat([6, 7, 8]) // [1, 2, 3, 4, 5, 6, 7, 8]

항목 제거
Array.filter() 함수는 특정 조건을 만족하는 요소를 모아서 새로운 배열을 반환한다.

// Array.filter()
const arr = [-3, -2, -1, 0, 1, 2, 3]
const newArr = arr.filter(nums => nums > 0) // [1, 2, 3]

Array.findIndex() 함수는 특정 조건을 만족하는 첫 번째 요소의 index를 반환한다. 이를 Array.splice() 함수와 함께 사용하면 특정 항목을 제거할 수 있다. Array.splice() 함수는 두 개의 매개변수를 받는다. 첫 번째 매개변수는 제거할 항목의 인덱스를 의미하고, 두 번째 매개변수는 제거할 항목의 인덱스로부터 몇 번째 인덱스 전까지 제거할 것인지를 알려 준다.

const arr = [-3, -2, -1, 0, 1, 2, 3]
const index = arr.findIndex(nums => nums === 0) // 3
const newArr = arr.splice(index, 1) // [-3, -2, -1, 1, 2, 3]

항목 수정
Array.map() 함수를 사용하면 편리하게 수정할 수 있다. 기본적으로 Array.map() 함수는 배열의 모든 요소에 관여하지만, 조건문을 사용한다면 특정 항목만 수정하는 것이 가능하다.

const arr = [-2, -1, 0, 1, 2]
const newArr = arr.map(num => num === 0 ? 10 : num) // [-2, -1, 10, 1, 2]

React-Native

FlatList

import { FlatList } from 'react-native

data 속성의 값으로 배열을 설정하고, renderItem 속성을 통해 배열 안의 각 원소 데이터에 접근할 수 있다.

keyExtractor 속성은 각 항목의 고유값을 추출하는 값으로, reactkey props와 동일하다고 이해하면 될 것 같다. 이 때, keyExtractor의 값은 항상 문자열 타입이어야 하기 때문에 Number 타입일 경우 Object.toString() 메서드를 호출하여 문자열을 반환해주어야 한다.

Alert

Alert APIalert() 함수를 통해 사용자에게 알림창을 띄울 수 있고, 이 때 되돌아오는 응답에 따라 여러가지 작업을 실행할 수 있다.

const remove = () => {
  Alert.alert(
    '삭제', // 제목
    '정말로 삭제하시겠습니까?', // 질문
    [
      {text: '취소', onPress: () => {}, style: 'cancle'},
      {
        text: '삭제',
        onPress: () => {
          remove // 삭제 함수 호출
        },
        style: 'destructive'
      },
    ],
    {canclable: true, onDismiss: () => {}},
  );
}

alert() 함수는 총 네 개의 매개변수를 받는다. 첫 번째, 두 번째 매개변수는 각각 알림창의 제목과 질문을 의미한다. 세 번째 매개변수는 선택지와, 그 선택지를 선택했을 때 실행되는 함수, 선택지의 스타일 등의 정보가 포함된 배열이다. 마지막으로 네 번째는 Option 객체로, canclable 값을 통해 Alert 박스 바깥 영역을 터치하거나 취소 버튼을 눌렀을 때 Alert 창이 닫히도록 설정할 수 있다. 이 때, onDismissAlert 창이 닫힐 때 호출되는 함수이다.

AsyncStorage

브라우저에서 사용하는 LocalStorage와 매우 유사하다. LocalStorage에서 사용하는 getItem, setItem, clear 등과 동일한 메서드가 존재하고, 값을 저장할 때도 LocalStorage와 마찬가지로 문자열 타입으로 저장해야 한다.

다만, AsyncStorage는 비동기적으로 작동한다는 것이 LocalStorage와 비교되는 가장 큰 차이점이다. 그래서 AsyncStorage는 값을 조회하거나 설정할 때 Promise를 반환한다.

라이브러리 설치
이전에는 AsyncStorageReact-Native에 내장되어 있었지만, 현재에는 라이브러리로 분리되어 있기 때문에 사용하려면 별도로 설치해주어야 한다.

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

최대 용량 설정
Android에서는 너무 많은 데이터를 저장하지 못하도록 AsyncStorage의 최대 용량을 6MB로 제한하고 있다. 최대 용량 설정을 변경하고자 한다면 android/gradle.properties 파일에 다음과 같은 코드를 추가하면 된다.

AsyncStorage_db_size_in_MB=10

한계
AsyncStorage는 문자열 타입으로만 데이터를 저장할 수 있기 때문에, 다루는 데이터의 용량이 커질수록 성능이 떨어진다.

따라서 소규모 데이터를 다루는 경우에만 AsyncStorage를 사용하는 것이 권장되고, 데이터의 규모가 커진다면 realm이나 react-native-sqlite-storage의 사용을 고려하는 것이 좋다.

profile
돌멩이도 개발 할 수 있다

0개의 댓글