React数据管理与服务器端渲染技术全解析
立即解锁
发布时间: 2025-09-04 01:48:07 阅读量: 8 订阅数: 34 AIGC 


React 18实战:高效开发指南
# React 数据管理与服务器端渲染技术全解析
## 一、React 上下文 API 的使用
### 1.1 用提供者包装组件
在 React 中使用上下文(Context)分为两个部分,首先是用上下文提供者(Context Provider)包装应用。通常,所有提供者都定义在父组件中,以下代码可添加到 `App.tsx` 中:
```typescript
// Providers
import IssueProvider from '../contexts/Issue'
// Components
import Issues from './Issues'
const App = () => {
return (
<IssueProvider url="https://api.github.com/repos/ContentPI/ContentPI/issues">
<Issues />
</IssueProvider>
)
}
export default App;
```
这里我们用 `IssueProvider` 包装了 `Issues` 组件,这意味着在 `Issues` 组件内部可以消费上下文并获取 `issues` 值。需要注意的是,如果忘记用提供者包装组件,将无法在组件内访问上下文,而且可能不会收到错误消息,只会遇到未定义的数据,难以定位问题。
### 1.2 使用 useContext 消费上下文
若已在 `App.tsx` 中放置了 `IssueProvider`,就可以在 `Issues` 组件中使用 `useContext` Hook 来消费上下文:
```typescript
// Dependencies
import { FC, useContext } from 'react'
// Contexts
import { IssueContext, Issue } from '../contexts/Issue'
const Issues: FC = () => {
const { issues, url } = useContext(IssueContext)
return (
<>
<h1>ContentPI Issues from Context</h1>
{issues.map((issue: Issue) => (
<p key={`issue-${issue.number}`}>
<strong>#{issue.number}</strong> {' '}
<a href={`${url}/${issue.number}`}>{issue.title}</a> {' '}
{issue.state}
</p>
))}
</>
)
}
export default Issues
```
如果一切操作正确,就能看到问题列表。上下文 API 在将应用与数据分离并进行数据获取时非常有用,它还有多种用途,如主题设置或传递函数,具体取决于应用需求。
## 二、使用 SWR 实现 React Suspense
### 2.1 React Suspense 简介
React Suspense 在 React 16.6 中引入,它允许在满足特定条件之前暂停组件渲染,可以渲染一个加载组件或任何内容作为 Suspense 的回退(fallback)。目前,它主要有两个用例:
- 代码分割:当分割应用并等待用户访问的代码块下载时。
- 数据获取:在获取数据时。
在这两种情况下,都可以渲染一个回退内容,通常可以是加载 spinner、加载文本,甚至是占位骨架(placeholder skeleton)。
### 2.2 SWR 简介
Stale-While-Revalidate(SWR)是一个用于数据获取的 React Hook,它是一种 HTTP 缓存失效策略。SWR 策略是先从缓存返回数据(旧数据),然后发送获取请求(重新验证),最后返回最新数据。它由创建 Next.js 的 Vercel 公司开发。
### 2.3 构建 Pokedex
为了更好地解释 React Suspense 和 SWR,我们来构建一个 Pokedex。步骤如下:
1. **安装包**:
```bash
npm install swr react-loading-skeleton styled-components
```
2. **创建 fetcher 文件**:在 `src/components/Pokemon/fetcher.ts` 中创建:
```typescript
const fetcher = (url: string) => {
return fetch(url).then((response) => {
if (response.ok) {
return response.json()
}
return {
error: true
}
})
}
export default fetcher
```
这里,如果响应不成功,会返回一个包含错误信息的对象,以防止 API 返回 404 错误导致应用崩溃。
3. **配置 SWRConfig 并启用 Suspense**:修改 `App.tsx`:
```typescript
import { SWRConfig } from 'swr'
import PokeContainer from './Pokemon/PokeContainer'
import fetcher from './Pokemon/fetcher'
import { StyledPokedex, StyledTitle } from './Pokemon/Pokemon.styled'
const App = () => {
return (
<>
<StyledTitle>Pokedex</StyledTitle>
<SWRConfig value={{ fetcher, suspense: true }}>
<StyledPokedex>
<PokeContainer />
</StyledPokedex>
</SWRConfig>
</>
)
}
export default App
```
这里用 `SWRConfig` 包装了 `PokeContainer` 组件,以便能够获取数据。
4. **添加第一个 Suspense**:在 `src/components/Pokemon/PokeContainer.tsx` 中:
```typescript
import { FC, Suspense } from 'react'
import Pokedex from './Pokedex'
const PokeContainer: FC = () => {
return (
<Suspense fallback={<h2>Loading Pokedex...</h2>}>
<Pokedex />
</Suspense>
)
}
export default PokeContainer
```
这里为第一个 Suspense 定义了一个回退内容“Loading Pokedex...”,可以是任何 React 组件或纯文本。
5. **使用 useSWR Hook 获取数据**:在 `src/components/Pokemon/Pokedex.tsx` 中:
```typescript
import { FC, Suspense } from 'react'
import useSWR from 'swr'
import LoadingSkeleton from './LoadingSkeleton'
import Pokemon from './Pokemon'
import { StyledGrid } from './Pokemon.styled'
const Pokedex: FC = () => {
const { data: { results } } = useSWR('https://pokeapi.co/api/v2/pokemon?limit=150')
return (
<>
{results.map((pokemon: { name: string }) => (
<Suspense fallback={<StyledGrid><LoadingSkeleton /></StyledGrid>}>
<Pokemon key={pokemon.name} pokemonName={pokemon.name} />
</Suspense>
))}
</>
)
}
export default Pokedex
```
这里获取了前 150 只宝可梦的数据,对结果进行映射以渲染每只宝可梦,并为每个宝可梦添加了一个 Suspense 组件和一个 `LoadingSkeleton` 回退内容。
6. **渲染宝可梦数据**:在 `src/components/Pokemon/Pokemon.tsx` 中:
```typescript
import { FC } from 'react'
import useSWR from 'swr'
import { StyledCard, StyledTypes, StyledType, StyledHeader } from './Pokemon.styled'
type Props = {
pokemonName: string
}
const Pokemon: FC<Props> = ({ pokemonName }) => {
const { data, error } = useSWR(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`)
if (error || data.error) {
return <div />
}
if (!data) {
return <div>Loading...</div>
}
const { id, name, sprites, types } = data
const pokemonTypes = types.map((pokemonType: any) => pokemonType.type.name)
return (
<StyledCard pokemonType={pokemonTypes[0]}>
<StyledHeader>
<h2>{name}</h2>
<div>#{id}</div>
</StyledHeader>
<img alt={name} src={sprites.front_default} />
<StyledTypes>
{pokemonTypes.map((pokemonType: string) => (
<StyledType key={pokemonType}>{pokemonType}</StyledType>
))}
</StyledTypes>
</StyledCard>
)
}
export default Pokemon
```
这个组件将宝可梦的所有数据(ID、名称、精灵图和类型)整合并渲染出来。
### 2.4 样式文件
以下是 `Pokemon.styled.
0
0
复制全文
相关推荐










