了解 Suspense 和 React Hooks

问题描述 投票:0回答:2

我正在努力寻找使用 SuspenseReact hooks 的问题。

下面的 React 代码有几个关键问题

import { Suspense, useState, useEffect } from 'react';

const SuspensefulUserProfile = ({ userId }) => {
  const [data, setData] = useState({});
  useEffect(() => {
    fetchUserProfile(userId).then((profile) => setData(profile));
  }, [userId, setData])
  return (
    <Suspense>
      <UserProfile data={data} />
    </Suspense>
  );
};
const UserProfile = ({ data }) => {
  return (
    <>
      <h1>{data.name}</h1>
      <h2>{data.email}</h2>
    </>
  );
};
const UserProfileList = () => {
  <>
    <SuspensefulUserProfile userId={1} />
    <SuspensefulUserProfile userId={2} />
    <SuspensefulUserProfile userId={3} />
  </>
};

让我知道它们是什么。

我发现了两个关键问题。

  • setdata
    依赖数组中滥用
    useEffect
  • 没有提供
    suspense
    fallback
    道具。

我认为还剩下一个关键问题。

一个奇怪的事情是为什么

userId
需要包含在依赖项数组中。

javascript reactjs typescript react-hooks react-suspense
2个回答
16
投票

您滥用了

Suspense
的核心,至少在数据获取悬念可用之前是这样。

Suspense 当前仅适用于

React.lazy
组件,不适用于应用程序的任意“加载”状态。例如,React 应该如何判断你的
data
正在加载?

Suspense
的唯一用途是允许在 React 加载惰性组件时显示一些回退。对于其他类型的延迟加载应用程序数据,您可以实现自己的后备,如下所示:

const SuspensefulUserProfile = ({ userId }) => {
  const [data, setData] = useState();

  useEffect(() => {
    fetchUserProfile(userId).then(setData);
  }, [userId])

  return data ? <UserProfile data={data} /> : 'Loading...';
};

编辑:反应 19

React 19 现在支持一流的加载状态。您可以按如下方式修改您的代码:

import { Suspense, useMemo, use } from 'react';

const SuspensefulUserProfile = ({ userId }) => {
  return (
    <Suspense>
      <UserProfile userId={userId} />
    </Suspense>
  );
};

const UserProfile = ({ userId }) => {
  const promise = useMemo(() => fetchUserProfile(userId), [userId])
  const data = use(promise)

  return (
    <>
      <h1>{data.name}</h1>
      <h2>{data.email}</h2>
    </>
  );
};

const UserProfileList = () => {
  <>
    <SuspensefulUserProfile userId={1} />
    <SuspensefulUserProfile userId={2} />
    <SuspensefulUserProfile userId={3} />
  </>
};

7
投票

主要问题是您需要使用所谓的 Suspense 集成 来执行数据获取并与

<Suspense>
组件交互。

通常,

<UserProfile>
组件会同步消耗资源(在本例中为您的data
),并在资源尚不可用时
挂起组件,导致<Suspense>
暂时渲染其
fallback
 prop(您尚未指定)。当资源可用时,
<UserProfile>
会重新渲染,并同步返回消耗的资源。

我发布了一个名为

suspense-service

 的 Suspense 集成,它允许您使用封装 React Context API 的服务来使用异步函数定义的资源。

通过稍微修改示例代码,下面是

suspense-service

 的演示:

// import { Fragment, Suspense } from 'react'; const { Fragment, Suspense } = React; // import { createService, useService } from 'suspense-service'; const { createService, useService } = SuspenseService; const fetchUserProfile = userId => { return new Promise(resolve => { setTimeout(resolve, 1000 + Math.random() * 1000); }).then(() => { return { name: `User ${userId}`, email: `user${userId}@example.com` }; }); }; const UserProfileService = createService(fetchUserProfile); const SuspensefulUserProfile = ({ userId }) => { return ( <UserProfileService.Provider request={userId}> <Suspense fallback={<h1>Loading User Profile...</h1>}> <UserProfile /> </Suspense> </UserProfileService.Provider> ); }; const UserProfile = () => { const data = useService(UserProfileService); return ( <Fragment> <h1>{data.name}</h1> <h2>{data.email}</h2> </Fragment> ); }; const UserProfileList = () => { return ( <Fragment> <SuspensefulUserProfile userId={1} /> <SuspensefulUserProfile userId={2} /> <SuspensefulUserProfile userId={3} /> </Fragment> ); }; ReactDOM.render(<UserProfileList />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<div id="root"></div>

© www.soinside.com 2019 - 2024. All rights reserved.