리액트 네이티브 0.74 — Yoga 3.0, 브릿지 없는 새로운 아키텍처 등

한정(Han Jung)
18 min readMay 12, 2024

--

원문: https://reactnative.dev/blog/2024/04/22/release-0.74

오늘 리액트 네이티브 0.74가 출시됩니다! 이번 릴리스에는 Yoga 3.0, 기본값으로 제공되는 브릿지 없는 새 아키텍처, 배치 처리된 onLayout 업데이트(새 아키텍처)가 포함되었습니다. 또한, 새 프로젝트의 기본 패키지 매니저로 Yarn 3이 추가되었습니다.

또한 사용이 중단된(deprecated) API와 PropTypes가 제거되고 PushNotificationIOS에 대한 변경 사항이 적용됩니다. 안드로이드 최소 지원 버전은 이제 SDK 23(안드로이드 6.0)이 되었습니다.

하이라이트

Yoga 3.0

새로운 레이아웃 동작

리액트 네이티브 0.74는 최신 버전의 레이아웃 엔진인 Yoga 3.0을 포함했습니다. Yoga 3.0은 스타일링을 보다 예측할 수 있게 만들어 레이아웃을 개선하고, 웹용으로 작성된 컴포넌트 렌더링을 지원합니다.

리액트 네이티브는 일부 잘못된 레이아웃 동작을 의도적으로 계속 유지하고 있습니다. 이를 수정하면 상당수의 실제 컴포넌트에 영향을 미치는 것으로 나타났습니다. 향후 리액트 네이티브 버전에서 레이아웃 규격 준수를 더욱 세부적으로 설정할 수 있게 될 것입니다.

⚠️ 경고 이전의 리액트 네이티브는 row-reverse 컨테이너에서 margin, padding 또는 border를 설정할 때 left/right(및 start/end) 가장자리를 뒤집었습니다. 이제 이러한 속성의 동작을 웹과 일치시켰습니다. 이전에 가장자리가 반전되도록 의도했던 코드가 계속 올바르게 렌더링 되게 하려면 수정이 필요할 수 있습니다.

align-content: 'space-evenly' 지원

Yoga 3.0에서는 alignContent: 'space-evenly'를 지원합니다. space-evenly는 여러 줄의 flex 컨테이너에서 줄과 컨테이너 가장자리 사이에 균등한 간격을 두고 줄을 분산시킵니다.

출처: World Wide Web 컨소시엄

position: 'static' 지원

ℹ️ 정보 > position: 'static'은 새로운 아키텍처에서만 지원합니다.

position: ‘static’으로 표시된 요소는 오프셋이 될 수 없으며, 절대 위치가 지정된 요소의 컨테이닝 블록을 결정할 때 고려되지 않습니다. 이를 통해 직계 부모가 아닌 상위 요소를 기준으로 요소를 위치시킬 수 있습니다.

녹색 <View>lefttop을 선언해 부모가 아닌 파란색 <View/>를 기준으로 배치되는 것을 확인할 수 있습니다.

position이 설정되지 않은 경우 리액트 네이티브는 계속해서 position: 'relative'를 기본값으로 사용합니다.

새로운 아키텍처: 기본값으로 제공되는 브릿지가 제거된 아키텍처

이번 릴리스에서는 새 아키텍처를 활성화할 때 브릿지가 없는 모드를 기본값으로 설정합니다. 브릿지가 없는 모드를 기본값으로 전환하는 자세한 내용은 이 글에서 확인할 수 있습니다. 브릿지가 없는 모드로의 보다 원활한 전환을 지원하기 위해 인터롭(Interop) 레이어를 개선하고 여러 라이브러리와 협력하여 바로 브릿지가 없는 모드를 작동할 수 있도록 했습니다.

브릿지 제거 뿐만 아니라 새로운 렌더러 인터롭 레이어도 개선했습니다. 가장 흥미로운 점은 이제 이 모드가 기본으로 활성화 되어 있어 이를 통과해야 하는 컴포넌트를 별도로 지정할 필요가 없다는 것입니다! 자세한 내용은 여기에서 확인할 수 있습니다.

마지막으로, 새 아키텍처에 대해 더 자세히 알고 싶으시다면 react-native-new-architecture저장소에서 문서를 찾아보세요. 새 아키텍처가 기본값이 되면 이 정보는 reactnative.dev에 통합될 것입니다.

새로운 아키텍처: 배치 처리된 onLayout 업데이트

이제 onLayout 콜백의 상태 업데이트가 배치 처리됩니다. 이전에는 onLayout 이벤트의 각 상태 업데이트가 새로운 렌더링 커밋을 발생시켰습니다.

function MyComponent(props) {
const [state1, setState1] = useState(false);
const [state2, setState2] = useState(false);

return (
<View>
<View
onLayout={() => {
setState1(true);
}}>
<View
onLayout={() => {
// 이 이벤트가 실행되면 state1의 새 값은 더 이상 여기에서 관찰할 수 없습니다.
setState2(true);
}}>
</View>
</View>
);
}

0.74에서는 setState1setState2 업데이트가 함께 배치 처리됩니다. 이 변경 사항은 리액트에서 이미 예상되는 동작이며 리렌더링을 줄일 수 있습니다.

🔥 위험 이 변경으로 인해 배치 처리되지 않은 상태 업데이트를 의도해서 사용하던 코드가 손상될 수 있습니다. 업데이터 함수 또는 이와 동등한 함수를 사용하려면 이 코드를 리팩토링해야 합니다.

새로운 프로젝트를 위한 Yarn 3

이제 Yarn 3은 리액트 네이티브 커뮤니티 CLI로 초기화된 새 프로젝트의 기본 자바스크립트 패키지 매니저로 제공됩니다.

Yarn 3.x는 리액트 네이티브 라이브러리와의 호환성을 제공하는 모드인 nodeLinker: node-module과 함께 사용됩니다. 이는 이전 기본값인 Yarn Classic(1.x, 사용이 중단됨)을 대체합니다. 기존 앱에서 Yarn 버전을 업그레이드하려면 이 가이드를 따르세요.

$ yarn --help
━━━ Yarn Package Manager - 3.6.4 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

$ yarn <command>

커뮤니티 CLI는 --pm 플래그를 통해 다른 패키지 관리자와 함께 프로젝트를 초기화하는 기능도 지원합니다(자세히 보기).

주요 변경 사항

안드로이드 최소 SDK 버전 상향 조정(안드로이드 6.0)

리액트 네이티브 0.74의 최소 안드로이드 SDK 버전 요구 사항이 23(안드로이드 6.0)로 상향되었습니다. 이전에는 안드로이드 5.0(API 21)였습니다. 이 변경 사항의 배경은 여기에서 확인할 수 있습니다.

보너스: 안드로이드 앱 크기 축소

최소 SDK 버전 상향과 함께 네이티브 빌드에 여러 개선 사항이 있어 사용자 기기의 앱 크기를 크게 줄일 수 있었습니다.

예를 들어, 리액트 네이티브 0.74로 새로 생성된 앱은 사용자 기기에서 약 13% 적은 공간을 차지하여 기기에서 약 4MB를 절약할 수 있습니다.

PropTypes 제거

0.74 이전 버전의 리액트 네이티브는 사용이 중단된 API인 PropTypes를 2017년 리액트 15.5 버전부터 계속 제공했습니다! 이제 리액트 네이티브에서 포함되어 있던 PropTypes를 제거하여 앱 크기(경량화된 번들에서 26.4kB)와 메모리 오버헤드를 줄였습니다.

제거된 PropTypes는 다음과 같습니다. Image.propTypes, Text.propTypes, TextInput.propTypes, ColorPropType, EdgeInsetsPropType, PointPropType, ViewPropTypes (커밋 참조).

앱이나 라이브러리가 PropTypes에 의존한다면 타입스크립트와 같은 타입 시스템으로 마이그레이션하는 것을 적극 권장합니다.

PushNotificationIOS API 변경(사용이 중단됨)

리액트 네이티브 0.74는 사용이 중단된 PushNotificationIOS 라이브러리를 제거하려는 조치를 취하고 있습니다. 이번 릴리스의 변경 사항은 이전 iOS API에 대한 참조를 제거하는 데 중점을 두고 있습니다. PushNotificationIOS는 Apple의 User Notification 프레임워크로 마이그레이션 되었으며 알림을 예약하고 처리하기 위한 새로운 API를 노출합니다.

다음 릴리스(0.75)에서는 이 라이브러리를 제거하여 리액트 네이티브 코어에서 커뮤니티 패키지인 @react-native-community/push-notification-ios로 이전할 계획입니다. 여전히 PushNotificationIOS를 사용 중이라면 다음 릴리스 전에 마이그레이션 해야 합니다.

API 변경

RCTPushNotificationManagerdidRegisterUserNotificationSettings 콜백은 작동하지 않았으며 삭제되었습니다.

RCTPushNotificationManager의 다음 콜백은 더 이상 사용되지 않으며 0.75에서 제거될 예정입니다.

+ (void)didReceiveLocalNotification:(UILocalNotification *)notification;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification;

getInitialNotification()을 사용하여 앱을 실행한 알림을 검색하려면 이제 RCTPushNotificationManager에서 initialNotification을 명시적으로 설정해야 합니다.

[RCTPushNotificationManager setInitialNotification:response.notification];

JS 측의 Notification 프로퍼티가 변경되었습니다. alertActionrepeatInterval은 이제 사용이 중단되며 0.75에서 제거될 예정입니다.

type Notification = {
...
// NEW: 지금부터 몇 초 후에 알림을 표시할지 정합니다.
fireIntervalSeconds?: ?number,

// CHANGED: 알림 예약에만 사용됩니다.
// `getScheduledLocalNotifications` 또는 `getDeliveredNotifications`를 사용하여 알림을 검색하는 경우
// null이 됩니다.
soundName?: ?string,

// 사용이 중단됨: iOS 레거시 UILocalNotification를 위해 사용되었습니다.
alertAction?: ?string,

// 사용이 중단됨: `fireDate` 또는 `fireIntervalSeconds` 를 사용하세요.
repeatInterval?: ?string,
};

마지막으로 PushNotificationIOS.removeEventListenerhandler 매개 변수는 사용되지 않으며 제거되었습니다

💡 마이그레이션 방법

iOS

AppDelegateUNUserNotificationCenterDelegate를 구현해야 합니다. 이 작업은 앱 시작 시 application:willFinishLaunchingWithOptions: 또는 application:didFinishLaunchingWithOptions:에서 수행되어야 합니다(자세한 내용은 애플 문서 참조).

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;

return YES;
}

알림이 도착하고 앱이 포그라운드에 있을 때 호출되는 userNotificationCenter:willPresentNotification:withCompletionHandler:를 구현해야 합니다. completionHandler를 사용하여 알림이 사용자에게 표시되는지 확인하고 그에 따라 RCTPushNotificationManager에 알립니다.

- (void)userNotificationCenter:UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)otification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
// PushNotificationIOS에서 'notification' 및 'localNotification' 이벤트가 트리거됩니다.
[RCTPushNotificationManager didReceiveNotification:notification];
// 사용자에게 알림을 표시할지 여부와 방법을 결정합니다.
completionHandler(UNNotificationPresentationOptionNone);
}

알림이 탭될 때 처리하려면 userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:를 구현하세요. userNotificationCenter:willPresentNotification:withCompletionHandler:에 표시되도록 포그라운드 알림을 설정한 경우 이러한 콜백 중 하나에서만 RCTPushNotificationManager에 알려야 합니다.

탭한 알림으로 인해 앱이 실행된 경우 setInitialNotification:을 호출하세요. 이전에 userNotificationCenter:willPresentNotification:withCompletionHandler:에 의해 알림이 처리되지 않은 경우 didReceiveNotification:도 호출하세요.

- (void)  userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
// 알림을 탭하여 앱을 실행한 경우 이 조건이 충족됩니다.
if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
// JS 측에서 getInitialNotification()을 사용하여 알림을 검색할 수 있도록 허용합니다.
[RCTPushNotificationManager setInitialNotification:response.notification];
}
// 이렇게 하면 PushNotificationIOS에서 '알림' 및 'localNotification' 이벤트가 트리거됩니다.
[RCTPushNotificationManager didReceiveNotification:response.notification];
completionHandler();
}

마지막으로, 다음 메서드를 삭제하고 대신 호출될 위의 콜백에 로직을 적용합니다.

application:didRegisterUserNotificationSettings:RCTPushNotificationManager의 해당 didRegisterUserNotificationSettings: 사용도 모두 삭제하세요.

예시: RNTester AppDelegate.mm을 참조하십시오.

JS

  • alertAction에 대한 모든 참조를 제거합니다.
  • removeEventListener에 대한 모든 호출에서 handler 인수를 제거합니다.
  • repeatInterval의 모든 사용을 fireDate 또는 fireIntervalSeconds를 사용하여 여러 알림을 실행하는 것으로 대체합니다.
  • getScheduledLocalNotifications()getDeliveredNotifications()에서 반환된 Notification에서 soundName에 접근할 경우 null이 됩니다.

Flipper 리액트 네이티브 플러그인 제거

리액트 네이티브 레이아웃, 네트워크 요청 및 기타 리액트 네이티브 플러그인 기능을 검사하기 위해 Flipper를 사용하는 것은 이제 더 이상 지원되지 않습니다. 0.74에서는 새로운 리액트 네이티브 프로젝트에서 네이티브 Flipper 라이브러리와 설정 코드가 제거되었습니다. 이는 종속성이 줄어들고 로컬 설정이 더 빨라진다는 것을 의미합니다(원본 RFC 참조).

앱에서 Flipper를 제거했을 때의 차이점은 업그레이드 헬퍼에서 확인할 수 있습니다. 기존 앱에서 Flipper를 유지하려면 관련 diff 줄을 무시하세요.

💡Flipper를 다시 통합하려면

Flipper는 안드로이드 또는 iOS 앱 디버깅을 위한 독립 실행형 도구로 계속 사용할 수 있으며, Flipper 문서(안드로이드 가이드, iOS 가이드)에 따라 수동으로 통합할 수 있습니다.

안드로이드 스튜디오 및 Xcode의 기본 디버깅 도구로 전환하는 데 투자하는 것이 좋습니다.

💡 Tip: Flipper 대체 Flipper 기능을 대체하는 전용 디버깅 도구가 많이 있습니다. 자세한 내용은 Jamon Holmgren이 작성한 리액트 네이티브 앱에 Flipper가 필요 없는 이유 글을 읽어보시기를 바랍니다.

자바스크립트 디버깅

0.74의 디버깅 옵션으로는 헤르메스 디버거를 사용하는 것을 권장합니다. 실험용 새 디버거를 사용해 볼 수도 있으며, 이 또한 Expo의 기본값입니다. 아직 초기 프리뷰 버전으로, 알려진 문제와 업데이트는 여기에서 확인할 수 있습니다.

다른 주요 변경 사항

공통

  • 스타일에서 start/end가 항상 쓰기 방향을 참조합니다.(#42251)

안드로이드

  • FabricUIManagerProvider에서 JSIModule*를 제거했습니다(#42059). 이 API는 오픈소스에서 사용되지 않았습니다. 대신 TurboModules를 사용하세요.
  • UIManagerModule.showPopupMenuUIManagerModule.dismissPopupMenu가 사용이 중단되었습니다(#42441).
  • 이 API는 @react-native/popup-menu-android npm 패키지로 마이그레이션되었으며, 0.75 버전에서 제거될 예정입니다.

iOS

  • iOS codegen CLI에서 configFilenameconfigKey 인수를 삭제했습니다(#41533).
  • bundleURL이 처리되는 방식이 변경되었습니다(#43994).
    * 이전에는 리액트 네이티브가 시작될 때 인스턴스 변수에 bundleURL이 설정되었고, 업데이트할 수 없었습니다.
    * 이제 bundleUrl은 필요할 때마다 재실행되는 함수이므로 새로고침 간에 다른 URL을 사용할 수 있습니다.
    * 이 변경 사항은 앱이 시작된 후 bundleURL 변수를 변경한 경우에만 영향을 미칩니다. 이 경우 변수를 업데이트하는 로직을 AppDelegatebundleURL 함수로 이동하세요.

전체 변경 사항은 전체 변경 로그를 참조하세요.

이미 알려진 이슈

iOS

  • 여러 개의 창을 사용할 때의 엣지 케이스: 기본 창이 비활성 상태이고 시스템에서 대화 상자를 표시하려고 할 때 대화 상자가 화면의 올바른 위치에 표시되지 않습니다. #44167에서 수정이 진행 중이며 0.74.1에서 제공될 예정입니다.

0.74로 업그레이드하기

업그레이드 문서 외에도 기존 프로젝트의 리액트 네이티브 버전 간 코드 변경 사항을 확인하려면 리액트 네이티브 업그레이드 헬퍼를 사용하세요.

새 프로젝트를 생성하려면 아래 명령어를 실행하세요.

npx react-native@latest init MyProject

Expo를 사용하는 경우, 리액트 네이티브 0.74는 Expo SDK 51에서 지원됩니다.

ℹ️ 정보 0.74는 이제 리액트 네이티브의 최신 안정 버전이며 0.71.x는 지원되지 않는 버전으로 전환됩니다. 자세한 내용은 리액트 네이티브 지원 정책을 참조하세요. 5월 초에 0.71의 최종 지원 종료 업데이트를 게시하는 것을 목표로 하고 있습니다.

--

--