10

我正在努力寻找使用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需要包含在依赖数组中。

4

2 回答 2

11

你滥用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...';
};
于 2020-10-12T20:13:47.413 回答
6

主要问题是您需要使用所谓的Suspense 集成来执行数据获取和与<Suspense>组件的接口。

通常,<UserProfile>组件会同步消耗资源data在这种情况下是您的),并在资源尚不可用时暂停<Suspense>组件,从而导致临时呈现其fallbackprop(您尚未指定)。当资源可用时,<UserProfile>将重新渲染,并同步返回消耗的资源。

我已经发布了一个名为 Suspense 的集成suspense-service,它允许您使用一个封装了 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/suspense-service@0.2.3"></script>
<div id="root"></div>

于 2020-10-11T05:56:19.893 回答