如何将从远程 API 获取的初始数据与 React.Suspense 集成?

How to integrate initial data fetching from a remote API, with React.Suspense?

我正在现有样板之上构建一个新的 React 应用程序。它使用延迟加载,结合 React.Suspense.

问题是,就像在大多数 React 应用程序中一样,每次应用程序加载时,我需要从服务器 获取一些初始元数据。我们称它为“getAppMetaData”。

那么问题是什么?问题是,当 getAppMetaData 待定时,我需要提供一些 loader/spinner。而这正是 React.Suspense 所做的:它显示了“回退”UI。当然我可以 运行 一个单独的加载器(实际上可以与后备 UI 相同),但这会产生一个用户体验问题,加载器的动画“重新启动” , 程序之间.

所以,问题是,我如何才能将其他异步操作“集成”到此暂停中?简而言之:“我的回退 UI 已经显示,而块(来自延迟加载)已加载 - 那么我如何让它也等待 getAppMetaData?”

这是我的路由器:

<ErrorBoundary>
     <Suspense fallback={<div className={styles.loader}><Loader /></div>}>
        <Switch>
          <ProtectedRoute exact component={Home} path="/">                    
          </ProtectedRoute>    
             <Route path="/lesson">
               <Lesson></Lesson>
             </Route>    
            <Route exact path="/login">
              <Login />
            </Route>
               <Route path="/about">
            <About />
            </Route>
            <Route path="*">
              <NotFound />
          </Route>
        </Switch>
      </Suspense>
    </ErrorBoundary>

React 文档指出,Relay 库应该用于此目的,但我不想为我的 API 调用使用任何特殊库,只是为了克服这个简单的问题。它还指出:

What If I Don’t Use Relay? If you don’t use Relay today, you might have to wait before you can really try Suspense in your app. So far, it’s the only implementation that we tested in production and are confident in.

我只需要将一个小的初始 API 调用集成到此过程中。如何做呢? 任何建议将不胜感激。

我会将 Suspense 的子组件移动到一个新组件中,并从该组件中读取数据。

将使用自定义函数 fetchData 加载数据,该函数将创建 promise 和 return 包含 read 方法的对象,如果数据不是,该方法将抛出 promise准备好了。

function fetchData() {
  let status = 'pending';
  let result;

  const promise = fetch('./data.json')
    .then(data => data.json())
    .then(r => {
      status = 'success';
      result = r;
    })
    .catch(e => {
      status = 'error';
      result = e;
    });

  return {
    read() {
      if (status === 'pending') {
        throw promise;
      } else if (status === 'error') {
        throw result;
      } else if (status === 'success') {
        return result;
      }
    }
  };
}

const dataWrapper = fetchData();

function AppBody() {
  const data = dataWrapper.read();

  // you can now manipulate the data
  return (
    <Switch>
      <ProtectedRoute exact component={Home} path="/"/>                    
      <Route path="/lesson" component={Lesson} />
      <Route exact path="/login" component={Login} />
      <Route path="/about" component={About} />
      <Route path="*" component={NotFound} />
    </Switch>
  )
}

function App() {
  return (
    <ErrorBoundary>
     <Suspense fallback={<div className={styles.loader}><Loader /></div>}>
       <AppBody/>
     </Suspense>
    </ErrorBoundary>
  );
}

这是一个stackblitz example

这段代码的灵感来源于此codesandbox from the react documentation