了解 Suspense 和 React Hooks
Understanding Suspense and React Hooks
我正在努力寻找使用 Suspense 和 React 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} />
</>
};
告诉我它们是什么。
我发现了两个关键问题。
- 在
useEffect
依赖项数组中滥用 setdata
- 没有提供
suspense
fallback
道具。
我觉得还有一个关键问题。
一件奇怪的事情是为什么 userId
需要包含在依赖数组中。
主要问题是您需要使用所谓的 Suspense integration 来执行数据获取并与 <Suspense>
组件交互。
通常情况下,<UserProfile>
组件会 consume a resource synchronously(在这种情况下是您的 data
),当资源不可用时 暂停 组件然而,导致 <Suspense>
暂时呈现其 fallback
道具(您尚未指定)。当资源可用时,<UserProfile>
会re-render,并同步返回消耗的资源。
我发布了一个名为 suspense-service
that lets you consume resources defined by an async function using a service that encapsulates the React Context API 的 Suspense 集成。
下面是 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>
你误用了Suspense
它的核心,至少在数据获取悬念可用之前是这样。
Suspense 目前仅适用于 React.lazy
组件,不适用于应用程序的任意 'loading' 状态。例如,React 应该如何确定您的 data
正在加载?
Suspense
的唯一用途是允许在 React 加载 惰性组件 时显示一些回退。对于其他类型的延迟加载应用程序数据,您可以实现自己的回退,如:
const SuspensefulUserProfile = ({ userId }) => {
const [data, setData] = useState();
useEffect(() => {
fetchUserProfile(userId).then(setData);
}, [userId])
return data ? <UserProfile data={data} /> : 'Loading...';
};
我正在努力寻找使用 Suspense 和 React 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} />
</>
};
告诉我它们是什么。
我发现了两个关键问题。
- 在
useEffect
依赖项数组中滥用setdata
- 没有提供
suspense
fallback
道具。
我觉得还有一个关键问题。
一件奇怪的事情是为什么 userId
需要包含在依赖数组中。
主要问题是您需要使用所谓的 Suspense integration 来执行数据获取并与 <Suspense>
组件交互。
通常情况下,<UserProfile>
组件会 consume a resource synchronously(在这种情况下是您的 data
),当资源不可用时 暂停 组件然而,导致 <Suspense>
暂时呈现其 fallback
道具(您尚未指定)。当资源可用时,<UserProfile>
会re-render,并同步返回消耗的资源。
我发布了一个名为 suspense-service
that lets you consume resources defined by an async function using a service that encapsulates the React Context API 的 Suspense 集成。
下面是 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>
你误用了Suspense
它的核心,至少在数据获取悬念可用之前是这样。
Suspense 目前仅适用于 React.lazy
组件,不适用于应用程序的任意 'loading' 状态。例如,React 应该如何确定您的 data
正在加载?
Suspense
的唯一用途是允许在 React 加载 惰性组件 时显示一些回退。对于其他类型的延迟加载应用程序数据,您可以实现自己的回退,如:
const SuspensefulUserProfile = ({ userId }) => {
const [data, setData] = useState();
useEffect(() => {
fetchUserProfile(userId).then(setData);
}, [userId])
return data ? <UserProfile data={data} /> : 'Loading...';
};