크로스 플랫폼/React-Native <JSX>

[React-Native/오픈소스활동] Suspense 사용 방법

TaeGyeong Lee 2023. 8. 15. 21:20

 

개요

이슈 작성자가 이슈를 삭제하였습니다. 이슈 스크린샷이 없다는 점 참고 부탁드립니다.

React-Native에서 Suspense가 동작하지 않는다는 이슈가 있었습니다. 

Suspense는...

  • React 18에서 공식적으로 지원하는 컴포넌트
  • React-Native에서도 Suspense를 사용할 수 있음
  • 써드파티 라이브러리 수준에서 Suspense를 쉽게 활용할 수 있도록 지원
  • 따라서 이를 지원하는 써드파티 라이브러리(react-query 등)를 사용하는 것이 편함
  • 직접 구현하는 방법 중 하나로 promise객체를 다루는 함수를 추가로 작성하는 방법이 있음

 

문제 분석

이슈 작성자는 Suspense의 올바른 사용법을 숙지하지 않은 상태로 Suspense가 동작하지 않는다고 이슈를 생성

 

조치

Suspense 지원 라이브러리 미사용 예제 코드 및 구현 스크린샷을 첨부하여 이슈에 답변

[ App.tsx 소스 코드 ]

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 */

import React, {Suspense} from 'react';
import {ActivityIndicator, SafeAreaView, View} from 'react-native';
import MyComponents from './MyComponents';

function App(): JSX.Element {
  return (
    <SafeAreaView style={{flex: 1}}>
      <Suspense
        fallback={
          <View style={{height: '100%', width: '100%', alignItems: 'center'}}>
            <ActivityIndicator size="large" color={'#00ff00'} />
          </View>
        }>
        <MyComponents />
      </Suspense>
    </SafeAreaView>
  );
}

export default App;

 

[ MyComponents.tsx 소스 코드 ]

callApi 함수에서 받은 객체를 wrapPromise로 전달하는 것이 무엇인지를 이해하면 Suspense가 자식 컴포넌트의 상태를 어떻게 확인하는 지 짐작할 수 있습니다.

import React, {useEffect, useState} from 'react';
import {FlatList, Text} from 'react-native';

const MyComponent = () => {
  const [data, setData] = useState([]);

  // wrapPromise
  const wrapPromise = (promise: Promise<any>) => {
    let status = 'pending';
    let result: Promise<any>;

    const suspender = promise.then(
      res => {
        status = 'success';
        result = res;
      },
      err => {
        status = 'error';
        result = err;
      },
    );

    return () => {
      switch (status) {
        case 'pending':
          throw suspender;
        case 'error':
          throw result;
        default:
          return result;
      }
    };
  };

  const callApi = async () => {
    const url = 'https://jsonplaceholder.typicode.com/todos';

    const response = await fetch(url);
    const result = await response.json();
    return result;
  };

  useEffect(() => {
    const dataPromise = callApi();
    setData(wrapPromise(dataPromise));
  }, []);

  return (
    <FlatList
      data={data}
      renderItem={({item}) => <Text>{item.title}</Text>}
      keyExtractor={item => String(item.id)}
    />
  );
};

export default MyComponent;

 

[ 구현 스크린샷 ]

데이터를 성공적으로 가져오기 전 Suspend에 의해 로딩 컴포넌트가 잠깐 뜨는 것을 확인할 수 있습니다.

 

[ 이슈 작성자 답변 ] 

이슈 작성자로부터 답변을 받았습니다. 그 후 이슈는 삭제되었습니다. (?)

 

관련 링크

 

Suspense's fallback component is never displayed · Issue #38976 · facebook/react-native

Description I am trying to use Suspense with react native's new architecture for ios. Below is my code <Suspense fallback={ <View style={{height: '100%', width: '100%', alignItems: 'center'}}> <Act...

github.com

 

<Suspense> – React

The library for web and native user interfaces

react.dev

 

Suspense의 동작 원리

React v18에서 공식 릴리즈된 Suspense에 대해 파헤쳐보자.

velog.io