1

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

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

那么问题是什么?问题是,虽然 getAppMetaData 处于待处理状态,但我需要提供一些加载器/微调器。这正是 React.Suspense 所做的:它显示了“后备”用户界面。当然,我可以运行一个单独的加载程序(实际上可以与备用 UI 相同),但这会产生 UX 问题,加载程序的动画在程序之间“重新启动”。

所以,问题是,我如何将其他异步操作“集成”到这个暂停中?简而言之:“我的后备 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 调用使用任何特殊库,只是为了克服这个简单问题。它还指出:

如果我不使用中继怎么办?如果您今天不使用 Relay,您可能需要等待才能真正在您的应用中尝试 Suspense。到目前为止,这是我们在生产中测试并有信心的唯一实现。

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

4

1 回答 1

1

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

数据将使用自定义函数加载,该函数fetchData将创建 Promise 并返回一个包含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示例

这段代码的灵感来自react 文档中的这个代码

于 2021-09-14T18:14:47.803 回答