[MOBILE-004][기초] 화면 상태와 앱 생명주기를 안전하게 연결하기
페이지 정보

본문
[이번 수업]
React Native에서 `useState`로 버튼 횟수를 관리하고, 앱의 전경·백그라운드 변화를 `useEffect`로 구독하고 정리합니다.
[선수지식]
JavaScript 함수·배열과 React 컴포넌트의 기초가 필요합니다. Node.js LTS와 Expo Go를 준비하세요.
[학습목표]
1. 화면 상태와 앱 생명주기 상태를 구분한다.
2. 이전 값을 바탕으로 상태를 안전하게 갱신한다.
3. 생명주기 이벤트를 구독하고 컴포넌트가 사라질 때 해제한다.
[핵심개념]
상태(state)는 컴포넌트가 기억할 값입니다. `useState(0)`은 현재 값과 갱신 함수를 돌려줍니다. 새 값이 이전 값에 의존하면 `setCount(value => value + 1)`처럼 함수로 갱신합니다.
React Native `AppState`는 화면 이동이 아니라 앱 전체의 상태를 알려 줍니다. `active`는 전경 실행, `background`는 다른 앱이나 홈 화면 뒤에 있는 상태이며 iOS에는 전환 중인 `inactive`도 있습니다. 시작 값이 없을 가능성은 `unknown`으로 처리합니다.
`useEffect`는 외부 시스템과 동기화할 때 사용합니다. 빈 의존성 배열 `[]`로 AppState를 구독하고, 정리 함수에서 `subscription.remove()`를 호출합니다. 정리를 빼면 리스너가 겹칠 수 있습니다.
메모리 상태는 영구 저장이 아닙니다. 운영체제가 앱 프로세스를 종료하면 count는 초기값으로 돌아가므로 재실행 뒤에도 필요한 값은 별도로 저장해야 합니다.
[따라하기]
Node.js LTS 설치 후 `npx create-expo-app@latest lifecycle-demo`를 실행하고 `app/index.tsx`를 아래 내용으로 바꾸세요.
```tsx
import { useEffect, useState } from 'react';
import { AppState, Button, StyleSheet, Text, View } from 'react-native';
export default function HomeScreen() {
const initialState = AppState.currentState ?? 'unknown';
const [count, setCount] = useState(0);
const [appState, setAppState] = useState(initialState);
const [history, setHistory] = useState([initialState]);
useEffect(() => {
const subscription = AppState.addEventListener('change', (nextState) => {
setAppState(nextState);
setHistory((items) => [...items.slice(-3), nextState]);
});
return () => subscription.remove();
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>카운트: {count}</Text>
<Button title="1 증가" onPress={() => setCount((v) => v + 1)} />
<Text>현재 앱 상태: {appState}</Text>
<Text>최근 상태: {history.join(' → ')}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, gap: 16, padding: 24, justifyContent: 'center' },
title: { fontSize: 24, fontWeight: 'bold' },
});
```
`npx expo start`를 실행합니다. Windows PowerShell, macOS, Linux에서 명령은 같습니다. 실제 기기에서 버튼을 두 번 누르면 ‘카운트: 2’가 보입니다. 홈 화면에 다녀오면 최근 상태에 보통 `active → background → active`가 기록되며 iOS에서는 `inactive`가 나타날 수도 있습니다.
[흔한 실수]
렌더링 중 이벤트를 구독하거나 정리를 빼면 중복 리스너가 생깁니다. 이전 count를 쓸 때는 함수로 갱신하세요. 계산 가능한 문구를 별도 상태로 복제하면 값이 어긋나기 쉽습니다.
[보안 주의]
민감값을 화면 상태나 로그에 두지 마세요. 백그라운드에서는 불필요한 카메라·위치 작업을 멈추고 앱 전환 화면의 노출도 확인하세요. AppState만으로 인증을 판단하지 말고 서버 권한 검증과 안전한 저장소를 사용합니다. 실습은 본인 기기에서 수행하세요.
[직접 해볼 과제]
1. background가 기록된 횟수를 화면에 표시하세요.
2. history가 최근 4개가 아니라 최근 6개를 보관하도록 수정하세요.
3. 정리 함수를 제거했을 때 생길 문제를 코드로 비교한 뒤 즉시 복원하세요.
[확인문제]
1. `useState`의 갱신 함수 형식을 쓰는 이유는 무엇인가요?
2. AppState의 `active`와 `background`는 무엇을 뜻하나요?
3. Effect가 반환하는 정리 함수는 어떤 문제를 예방하나요?
[다음 학습]
MOBILE-005에서는 네트워크 요청과 오프라인 처리를 배웁니다.
[공식 참고 자료]
React Native AppState: https://reactnative.dev/docs/appstate
React useState: https://react.dev/reference/react/useState
React useEffect: https://react.dev/reference/react/useEffect
Expo 프로젝트 생성: https://docs.expo.dev/get-started/create-a-project/
React Native에서 `useState`로 버튼 횟수를 관리하고, 앱의 전경·백그라운드 변화를 `useEffect`로 구독하고 정리합니다.
[선수지식]
JavaScript 함수·배열과 React 컴포넌트의 기초가 필요합니다. Node.js LTS와 Expo Go를 준비하세요.
[학습목표]
1. 화면 상태와 앱 생명주기 상태를 구분한다.
2. 이전 값을 바탕으로 상태를 안전하게 갱신한다.
3. 생명주기 이벤트를 구독하고 컴포넌트가 사라질 때 해제한다.
[핵심개념]
상태(state)는 컴포넌트가 기억할 값입니다. `useState(0)`은 현재 값과 갱신 함수를 돌려줍니다. 새 값이 이전 값에 의존하면 `setCount(value => value + 1)`처럼 함수로 갱신합니다.
React Native `AppState`는 화면 이동이 아니라 앱 전체의 상태를 알려 줍니다. `active`는 전경 실행, `background`는 다른 앱이나 홈 화면 뒤에 있는 상태이며 iOS에는 전환 중인 `inactive`도 있습니다. 시작 값이 없을 가능성은 `unknown`으로 처리합니다.
`useEffect`는 외부 시스템과 동기화할 때 사용합니다. 빈 의존성 배열 `[]`로 AppState를 구독하고, 정리 함수에서 `subscription.remove()`를 호출합니다. 정리를 빼면 리스너가 겹칠 수 있습니다.
메모리 상태는 영구 저장이 아닙니다. 운영체제가 앱 프로세스를 종료하면 count는 초기값으로 돌아가므로 재실행 뒤에도 필요한 값은 별도로 저장해야 합니다.
[따라하기]
Node.js LTS 설치 후 `npx create-expo-app@latest lifecycle-demo`를 실행하고 `app/index.tsx`를 아래 내용으로 바꾸세요.
```tsx
import { useEffect, useState } from 'react';
import { AppState, Button, StyleSheet, Text, View } from 'react-native';
export default function HomeScreen() {
const initialState = AppState.currentState ?? 'unknown';
const [count, setCount] = useState(0);
const [appState, setAppState] = useState(initialState);
const [history, setHistory] = useState([initialState]);
useEffect(() => {
const subscription = AppState.addEventListener('change', (nextState) => {
setAppState(nextState);
setHistory((items) => [...items.slice(-3), nextState]);
});
return () => subscription.remove();
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>카운트: {count}</Text>
<Button title="1 증가" onPress={() => setCount((v) => v + 1)} />
<Text>현재 앱 상태: {appState}</Text>
<Text>최근 상태: {history.join(' → ')}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, gap: 16, padding: 24, justifyContent: 'center' },
title: { fontSize: 24, fontWeight: 'bold' },
});
```
`npx expo start`를 실행합니다. Windows PowerShell, macOS, Linux에서 명령은 같습니다. 실제 기기에서 버튼을 두 번 누르면 ‘카운트: 2’가 보입니다. 홈 화면에 다녀오면 최근 상태에 보통 `active → background → active`가 기록되며 iOS에서는 `inactive`가 나타날 수도 있습니다.
[흔한 실수]
렌더링 중 이벤트를 구독하거나 정리를 빼면 중복 리스너가 생깁니다. 이전 count를 쓸 때는 함수로 갱신하세요. 계산 가능한 문구를 별도 상태로 복제하면 값이 어긋나기 쉽습니다.
[보안 주의]
민감값을 화면 상태나 로그에 두지 마세요. 백그라운드에서는 불필요한 카메라·위치 작업을 멈추고 앱 전환 화면의 노출도 확인하세요. AppState만으로 인증을 판단하지 말고 서버 권한 검증과 안전한 저장소를 사용합니다. 실습은 본인 기기에서 수행하세요.
[직접 해볼 과제]
1. background가 기록된 횟수를 화면에 표시하세요.
2. history가 최근 4개가 아니라 최근 6개를 보관하도록 수정하세요.
3. 정리 함수를 제거했을 때 생길 문제를 코드로 비교한 뒤 즉시 복원하세요.
[확인문제]
1. `useState`의 갱신 함수 형식을 쓰는 이유는 무엇인가요?
2. AppState의 `active`와 `background`는 무엇을 뜻하나요?
3. Effect가 반환하는 정리 함수는 어떤 문제를 예방하나요?
[다음 학습]
MOBILE-005에서는 네트워크 요청과 오프라인 처리를 배웁니다.
[공식 참고 자료]
React Native AppState: https://reactnative.dev/docs/appstate
React useState: https://react.dev/reference/react/useState
React useEffect: https://react.dev/reference/react/useEffect
Expo 프로젝트 생성: https://docs.expo.dev/get-started/create-a-project/
- 이전글[IOT-004][기초] GPIO로 버튼을 읽고 LED를 켜기 26.08.31
- 다음글[SWE-004][기초] 실패하는 테스트부터 시작하는 TDD와 테스트 더블 26.08.31
댓글목록
등록된 댓글이 없습니다.
