React悬念用法

React suspense usage

假设 fetchUserProfile 在别处定义。 Suspense 用法有什么问题吗?

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} />
  </>
);

如评论中所述,我建议您不要为此使用悬念。 Suspense for data loading 是一项实验性功能,如果您不明白到底发生了什么,您可能会陷入困境。

除了删除悬念和检查是否为空状态外,实现此类内容的标准方法与您现在拥有的差不多。例如:

const DataLoader = ({ userId }) => {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetchUserProfile(userId).then((profile) => setData(profile));
  }, [userId, setData])

  if (data === null) {
    return <div>Loading...</div>
  }
  return (
    <UserProfile data={data} />
  );
};

如果你想使用悬念,你需要反转你做事的方式。 Suspense 需要在执行数据加载的组件外部,然后你需要抛出一个 promise 以告诉 suspense 加载正在进行中:

const OuterComponent = () => {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <DataLoader />
    </Suspense>
  );
}

let data;

const DataLoader = () => {
  if (!data) {
    throw fetchUserProfile(userId)
      .then((profile) => { data = profile });
  }

  return <UserProfile data={data} />
}

请注意,数据需要在组件外部,因为一旦 promise resolves,suspense 将尝试再次渲染组件并且您的数据必须同步可用,否则您将抛出另一个 promise 并且进入无限循环。