[번역] React Native 0.77 - 새로운 스타일링 기능, Android의 16KB 페이지 지원, Swift 템플릿

오성준·2025년 3월 4일
0

React Native

목록 보기
11/15

원문: https://reactnative.dev/blog/2025/01/21/version-0.77

오늘 React Native 0.77을 출시하게 되어 기쁩니다!

이번 릴리스에는 display: contents, boxSizing, mixBlendMode, outline 관련 속성을 지원하여 더욱 강력한 레이아웃 옵션을 제공하는 등 새로운 스타일링 기능, 최신 Android 디바이스와 호환되도록 Android 16KB 페이지 지원 등 여러 가지 기능이 추가되었습니다. 또한 커뮤니티 템플릿을 Swift로 마이그레이션하여 현대화하는 한편, Objective-C를 선호하는 개발자를 위해 Objective-C와의 호환성을 계속 지원하고 유지해 나가고 있습니다.

하이라이트

  • 더 나은 레이아웃, 크기 조정 및 블렌딩을 위한 새로운 CSS 기능
  • Android 버전 15 지원 및 16KB 페이지 지원
  • 커뮤니티 CLI 및 템플릿 업데이트

Breaking Changes

  • Metro에서 console.log() 스트리밍 제거

하이라이트

더 나은 레이아웃, 크기 조정 및 블렌딩을 위한 새로운 CSS 기능

React Native 0.77은 React Native를 웹과 일치시키려는 우리의 목표를 더욱 진전시켰습니다. 앱의 레이아웃, 크기 조정 및 블렌딩을 더 잘 제어할 수 있도록 새로운 CSS 속성에 대한 지원이 추가되었습니다. 이러한 변경 사항은 복잡한 레이아웃을 단순화하고, 텍스처를 추가하고, 앱의 접근성을 높이는 데 도움이 될 수 있습니다.

정보
이 모든 새로운 기능은 New Architecture에서만 사용할 수 있습니다.

display: contents 로 더 간단한 레이아웃

display: contents 프로퍼티를 사용하면 요소가 레이아웃 구조에서 사라지지만 자식 요소는 여전히 부모 요소의 직접적인 자식인 것처럼 렌더링할 수 있습니다. 레이아웃에 영향을 주지 않고 자식 요소에 스타일을 적용하려는 스타일링 목적, 이벤트를 처리해야 하는 래퍼 컴포넌트를 만들 때 또는 ShadowTree와 상호작용해야 하는 경우에 유용할 수 있습니다.

기술적으로 말하자면, display: contents 는 레이아웃 상자를 생성하지 않고 요소를 렌더링하지만 요소의 하위 요소의 레이아웃 상자는 유지합니다. display: contents 이 있는 요소는 뷰 계층 구조에서 효과적으로 평탄화됩니다.

위젯을 눌렀을 때 알림을 표시하려는 이 예제를 살펴보겠습니다. 컨테이너 뷰 안에 빨간색 위젯이 있습니다.

// Container.jsx
function Container() {
  return (
    <View style={styles.container}>
      <Widget />
    </View>
  );
}

이제 실험적인 포인터 이벤트를 사용하여 그 아래의 컴포넌트를 눌렀을 때 사용자에게 경고하는 것을 목표로 하는 새로운 Alerting 래퍼 컴포넌트를 만들어 보겠습니다. 명확성을 위해 이 컴포넌트의 배경은 파란색으로 만들었습니다. 아래 컴포넌트와 비슷하게 보일 수 있습니다.

// Container.jsx
function Alerting({children}) {
  return (
    <View
      style={{backgroundColor: 'blue'}}
      onPointerDown={() => alert('Hello World!')}>
      {children}
    </View>
}

function Container() {
  return (
    <View style={styles.container}>
      <Alerting>
        <Widget />
      </Alerting>
    </View>
  );
}

이것은 우리가 원하는 대로 작동하지 않습니다. Alerting은 하위 Widget과 별도로 자체 경계를 가진 새 레이아웃 상자를 추가합니다. 래핑하는 요소의 스타일에 따라 시각적 및 기능적으로 상당한 변화가 발생할 수 있습니다. 이 예제에서는 빨간색 "Hello World" 상자만 탭했을 때 경고를 울리도록 하려고 할 때, 파란색 배경은 alert으로 탭에 반응합니다.

이 작업을 다시 시도하면 AlertingView 래퍼에 display: contents 를 설정하면서 사용자가 Widget의 원래 범위 내에서 누를 때만 알림이 표시됩니다. 이는 Alerting이 더 이상 자체 상자를 추가하지 않지만 Widget에서 버블링된 포인터 이벤트를 계속 관찰할 수 있기 때문입니다.

// Container.jsx
function Alerting({children}) {
  return (
    <View
      style={{display: 'contents'}}
      onPointerDown={() => alert('Hello World!')}>
      {children}
    </View>
  );
}

// ... function Container ...

Box sizing

boxSizing 프로퍼티는 요소의 다양한 크기 조정 프로퍼티(width, height, minWidth, minHeight 등)가 계산되는 방식을 정의합니다. boxSizingborder-box 인 경우 이러한 크기는 요소의 테두리 상자에 적용됩니다. content-box 인 경우 요소의 콘텐츠 상자에 적용됩니다. 기본값은 border-box이며, 이는 웹의 기본값과 다릅니다. 이 프로퍼티의 작동 방식에 대해 자세히 알아보려면 웹 문서를 참조하세요.

경고
border-box 는 지금까지 기본값으로 사용되어 왔으며, content-box 를 추가하기 전까지는 유일한 boxSizing 값이었습니다. 기본값을 변경하면 여러 레이아웃이 갑자기 깨질 수 있는 breaking change이었을 것입니다. 이전 버전과의 호환성을 보장하기 위해 border-box 를 기본값으로 유지하기로 결정했습니다.

border-boxcontent-box 의 차이점을 이해하려면 두 View 모두 padding: 20borderWidth: 10 이 있는 다음 예제를 살펴보십시오. border-box 를 사용할 때는 크기 조정에 border와 padding을 고려하고, content-box 를 사용할 때는 content만 고려합니다.

CSS mixBlendMode

mixBlendMode 프로퍼티를 사용하면 stacking context에서 요소가 다른 요소와 색상을 혼합하는 방식을 제어할 수 있습니다. 각 블렌딩 함수에 대한 전체 개요는 MDN 문서를 확인하세요.

혼합되는 항목을 보다 세밀하게 제어할 수 있도록 isolation 프로퍼티도 추가했습니다. Viewisolation: isolate 프로퍼티를 설정하면 View 가 강제로 stacking context를 형성합니다. 따라서 일부 상위 View 에 이 프로퍼티를 설정하여 mixBlendMode 가 있는 일부 하위 Viewisolated View 를 넘어 블렌딩되지 않도록 할 수 있습니다.

mixBlendMode Values

  • normal: 요소는 블렌딩하지 않고 배경 위에 그려집니다.
  • multiply: 소스 색상에 대상 색상을 곱하여 대상을 대체합니다.
  • screen: 배경 및 소스 색상 값의 보수를 곱한 다음 결과를 보색합니다.
  • overlay: 배경색 값에 따라 색상을 곱하거나 가립니다.
  • darken: 배경색과 소스 색상 중 더 어두운 색상을 선택합니다.
  • lighten: 배경 및 소스 색상 중 더 밝은 색상을 선택합니다.
  • color-dodge: 배경 색상을 밝게 하여 소스 색상을 반영합니다. 검정색으로 칠하면 변화가 없습니다.
  • hard-light: 소스 색상 값에 따라 색상을 곱하거나 스크린합니다. 이 효과는 배경에 강한 스포트라이트를 비추는 것과 유사합니다.
  • soft-light: 소스 색상 값에 따라 색상을 어둡게 또는 밝게 합니다. 이 효과는 배경에 확산 스포트라이트를 비추는 것과 유사합니다.
  • difference: 두 구성 색상 중 밝은 색상에서 어두운 색상을 뺍니다.
  • exclusion: difference 모드와 비슷한 효과를 내지만 대비가 더 낮습니다.
  • hue: 소스 색의 색조와 배경 색의 채도 및 명도를 사용하여 색상을 만듭니다.
  • saturation: 소스 색의 채도와 배경 색의 색조 및 광도를 사용하여 색상을 만듭니다.
  • color: 소스 색상의 색조와 채도 및 배경 색상의 광도를 사용하여 색상을 만듭니다. 이렇게 하면 배경의 회색 레벨이 유지되며 흑백 이미지에 색을 입히거나 컬러 이미지에 색조를 입힐 때 유용합니다.
  • luminosity: 소스 색의 광도와 배경 색의 색조 및 채도를 사용하여 색을 만듭니다. 이렇게 하면 color 모드의 효과와 반대의 효과가 생성됩니다.

Outline 프로퍼티

또한 outlineWidth, outlineStyle, outlineSpreadoutlineColor 를 도입했습니다. 이러한 outline 프로퍼티는 각각의 border 프로퍼티와 매우 유사하게 작동하지만 padding box 주변이 아닌 border box 주변에 렌더링됩니다. 이러한 프로퍼티를 사용하면 레이아웃에 영향을 주지 않고 outline을 그려서 요소를 강조할 수 있습니다.

자세한 내용은 MDN 문서를 확인하세요.

Android 버전 15 지원 및 16KB 페이지 지원

Android 15에서 강제적인 edge-to-edge

이전 릴리스에서 이미 Android 15를 지원하기 위한 몇 가지 작업을 수행했습니다. Android 15의 눈에 띄는 변경 사항 중 하나는 targetSdk 35로 앱을 빌드할 때 강제적인 edge-to-edge 디스플레이입니다.

이를 무시하면 앱의 UI가 손상될 수 있으므로 이를 처리하는 방법에 대한 이전 권장 사항을 참조하시기 바랍니다.

참고
앱에서 react-native-safe-area-context를 사용하는 경우 라이브러리가 이미 강제적인 edge-to-edge를 처리하고 있습니다.

Android용 16KB 페이지 크기 지원

Android 15는 16KB 메모리 페이지 크기를 지원하여 앱 등의 성능을 향상시킬 수 있지만, 이전의 4KB 기반 앱은 향후 기기에서 호환되지 않을 수 있습니다. 현재 개발자가 일부 기기에서 테스트하여 16KB 페이지 크기가 OS 기본값이 될 것에 대비할 수 있는 옵션 기능입니다.

0.77 릴리스에서 React Native는 16KB 페이지 크기를 완벽하게 지원하며, 개발자는 이를 사용하여 16KB 디바이스용 앱을 테스트하고 출시할 수 있습니다.

16KB 지원에 대한 자세한 내용은 공식 Android 개발자 사이트를 참조하세요.

커뮤니티 CLI 및 템플릿 업데이트

커뮤니티 CLI: react-native init 지원 중단

이 버전에서는 React Native 0.75에서 도입react-native init 명령어의 지원이 완전히 중단됩니다.

다시 한 번 말씀드리지만, 더 이상 react-native init 명령어를 사용할 수 없게 됩니다.

  • 새 프로젝트를 생성하는 전용 명령어가 있는 Expo와 같은 프레임워크 사용: npx create-expo-app
  • npx @react-native-community/cli init을 사용하여 커뮤니티 CLI를 직접 호출

커뮤니티 CLI: Metro에서 "run on iOS/Android" 키 핸들러 제거

이 버전에서는 Metro에서 'a' 및 'i' 키보드 단축키를 제거했습니다. 이 단축키는 run-androidrun-ios 커뮤니티 CLI 명령을 호출하는 데 사용되었습니다. 이러한 키보드 단축키는 개발자 경험을 악화시키고 거의 사용되지 않았습니다. 또한 터미널 출력을 조율하는 데는 프레임워크가 더 적합하다고 생각합니다.

이 변경 사항에 대한 자세한 내용은 이 전용 게시물에서 확인할 수 있습니다.

커뮤니티 템플릿: iOS 앱용 프로그래밍 언어로서의 Swift

정보
Expo를 사용하는 프로젝트는 이 변경 사항의 영향을 받지 않습니다.

이 변경을 통해 세 개의 파일(main.m, AppDelegate.hAppDelegate.mm)을 하나의 새로운 AppDelegate.swift로 대체하여 커뮤니티 템플릿을 간소화할 수 있었습니다.

업그레이드 헬퍼에서 다음과 같이 Objective-C에서 Swift로 변경된 것을 확인할 수 있습니다.

Swift로 마이그레이션할 필요가 없습니다. iOS 커뮤니티 템플릿의 Objective-C++ 변형은 계속 지원됩니다(여전히 RCTAppDependencyProvider를 통합해야 함). 새 프로젝트는 iOS 앱 언어로 Swift를 사용하여 생성되지만, 필요한 경우 언제든지 Objective-C로 다시 마이그레이션할 수 있습니다.

제한 사항

앱에 C++로 작성된 일부 로컬 모듈이 있는 경우 이 가이드에 표시된 대로 Swift에 등록할 수 없습니다.

앱이 이 범주에 속하는 경우, AppDelegate를 Swift로 마이그레이션하지 말고 앱에 Objective-C++를 계속 사용하세요.

React Native 코어는 iOS와 Android 및 기타 플랫폼 간의 코드 공유를 장려하기 위해 대부분 C++를 사용하여 개발되었습니다. Swift와 C++ 간의 상호 운용성은 아직 성숙하지도 안정적이지도 않습니다. 이 간극을 메우고 Swift로 마이그레이션할 수 있는 방법을 모색하고 있습니다.

RCTAppDependencyProvider

React Native 0.77에서는 앱이 서드파티 종속성을 로드하는 방식이 약간 변경되었습니다. 이는 커뮤니티 템플릿에 새로 추가된 줄로, 누락될 경우 런타임 문제가 발생할 수 있습니다. 앱에 반드시 추가하세요.

이에 해당하는 Objective-C 라인은 다음과 같습니다.

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
+++ #import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>


@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"<Your app Name>";
+++  self.dependencyProvider = [RCTAppDependencyProvider new];
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

// remaining of the AppDelegate

Breaking Changes

Metro에서 console.log() 스트리밍 제거

우리는 React Native 디버깅의 모든 측면이 안정적으로 작동하고 최신 브라우저 도구의 기능과 일치하기를 원합니다. 이 품질 기준을 충족하기 위해 원래 0.76에서 더 이상 사용되지 않던 Metro를 통한 로그 전달이 0.77에서 제거되었습니다.

이 통합은 기기에서 디버깅 대상과 통신하기 위해 커스텀 접근 방식에 의존했습니다. 이번 변경으로 Chrome Chrome DevTools Protocol(CDP)로만 전환합니다.

  • JS 로그를 보려면 로그 필터링, 리치 오브젝트 검사, Live Expressions 등을 지원하는 React Native 개발자 도구와 모든 기능을 갖춘 콘솔 패널을 사용하세요.
  • Expo 도구Radon IDE와 같은 타사 확장 프로그램을 통해 VS Code를 CDP 디버거로 연결할 수도 있습니다.
    • 이러한 통합은 React 팀에서 직접 지원하지 않는다는 점에 유의하세요. 하지만 2025년에 퍼스트 파티 VS Code 지원을 위해 노력하고 있습니다.
  • Expo는 계속해서 Expo CLI에서 로그 스트리밍을 제공합니다.

자세한 내용은 JavaScript 로그가 Metro를 떠나는 이유를 참조하세요.

다른 Breaking Changes

일반

  • Animation
    • 네이티브 루핑 애니메이션은 루프가 끝날 때마다 React 상태 업데이트를 보내지 않습니다.
  • Layout
    • 이제 ScrollView에서 고정 헤더의 position이 고려됩니다.
    • Absolute positioning이 이제 보다 규정을 준수하는 방식으로 작동합니다.
  • JS Modules
    • ReactFabricInternals 모듈이 제거됩니다.
      • 더 이상 액세스할 수 없습니다.
  • Native Modules
    • 이제 JS에서 터보모듈을 로드하는 데 NativeModules 객체를 사용할 수 있습니다.
      • 이렇게 하면 Native Modules와 Turbo Native Modules 간의 호환성이 향상됩니다.
  • Packages
    • dev-middleware: 프레임워크는 미들웨어 호스트를 기준으로 serverBaseUrl을 지정해야 합니다.
  • API Changes
    • 이미 무시되었으므로 AppRegistry 에서 useConcurrentRoot 에 대한 타입을 제거했습니다.
    • NativeMethods TypeScript 정의에서 refs 프로퍼티를 제거했습니다.
  • UX Changes
    • 개발 서버 키 명령어에서 "run on iOS" 및 "run on Android"을 제거합니다.

Android

  • Kotlin
    • 이 버전은 Kotlin 2.0.21을 기반으로 빌드되는 첫 번째 React Native 버전입니다. Kotlin 2.0의 변경 사항에 대한 자세한 내용은 언어 릴리스 노트에서 확인할 수 있습니다.
  • API Changes
    • Nullability
      • 이제 ReadableArray의 Non-primitive getters가 선택 사항으로 올바르게 타입 지정됩니다.
      • ReactHost.createSurface() 메서드를 null로 설정할 수 없습니다.
    • Renamed
      • DevSupportManagerBase.getCurrentContext()DevSupportManagerBase.getCurrentReactContext() 로 변경합니다.

또한 여러 API가 제거되거나 가시성이 제한되어 더 이상 액세스할 수 없게 되었습니다. 이러한 API는 내부용이며 React Native 개발자가 직접 사용할 필요가 없습니다. 아래에서 전체 목록을 확인할 수 있습니다.

제거된 Android API 목록
다음 패키지는 이제 내부 패키지이며 더 이상 액세스할 수 없습니다.

  • com.facebook.react.views.progressbar
  • com.facebook.react.views.safeareaview
  • com.facebook.react.modules.accessibilityinfo
  • com.facebook.react.modules.appstate
  • com.facebook.react.modules.clipboard
  • com.facebook.react.modules.devmodule
  • com.facebook.react.modules.reactdevtoolssettings
  • com.facebook.react.views.unimplementedview

다음 클래스는 이제 내부에 있거나 제거되었으므로 더 이상 액세스할 수 없습니다.

  • BackHandler.removeEventListener
  • BaseViewManagerInterface
  • BindingImpl
  • CompositeReactPackage
  • DebugOverlayTags
  • DefaultDevSupportManagerFactorycreate() 메서드
  • DevToolsReactPerfLogger
  • FabricComponents
  • ImageStoreManager
  • InteropModuleRegistry
  • NativeModulePerfLogger
  • NoopPrinter
  • NotThreadSafeViewHierarchyUpdateDebugListener
  • OkHttpCallUtil
  • PrinterHolder
  • Printer
  • ReactDebugOverlayTags
  • ReactNativeFlipper
  • ReactViewBackgroundManager
  • ReactViewGroup.getBackgroundColor()
  • ReactVirtualTextShadowNode
  • ReactVirtualTextViewManager
  • SimpleSettableFuture
  • SwipeRefreshLayoutManager
  • TaskCompletionSource
  • DefaultReactHost.getDefaultReactHost()의 매개 변수 jsBundleLoader

iOS

  • API Changes
    • Removed
      • RCTConstants.RCTGetMemoryPressureUnloadLevel
      • partialBatchDidFlush
      • RCTRuntimeExecutor
      • UseNativeViewConfigsInBridgelessMode
        • 적절한 기능 플래그로 대체
      • UseTurboModuleInteropForAllTurboModules
        • TurboModules를 위해 인터롭 레이어가 항상 켜져 있습니다.
    • Changed
      • CGColorRef의 사용을 UIColor로 대체
  • 이제 서드파티 종속성을 로드하려면 RCTAppDelegateRCTDependencyProvider를 사용해야 합니다.
  • CocoaPods은 컴파일 문제를 피하기 위해 모든 서드파티 종속성에 대해 C++ 버전을 설정합니다.

React 19?
React 19는 2024년 12월 6일에 출시되었습니다. 그 당시에는 이미 React Native 0.77의 브랜치를 잘라냈고 React Native 0.77의 RC를 세 번이나 릴리스했습니다. 이번 릴리스에서 React 19를 소개하기에는 React Native 0.77 릴리스가 너무 늦었습니다.

React 19는 React Native 0.78에서 제공될 예정이며, 이미 이 버전에 대한 브랜치를 잘라냈습니다. 다음 명령으로 새 앱을 생성하여 사용해 볼 수 있습니다.

npx @react-native-community/cli init YourReact19App --version 0.78.0-rc.0

profile
React Native 개발자

0개의 댓글