Filtering Games
GenreList
模板声明一个新接口 onSelectGenre
,该参数用于告知分类已经被选中,
App
组件获得通知,给 GenreList
组件设置 setSelectedGenre
,并把设置后的值 selectedGenre
给 GameGrid
组件触发渲染。
GameGrid
模板内,接收到 selectedGenre
对象,该对象作为查询参数用来传递给后端接口请求数据,所以又涉及到 useGame
组件,将 selectedGenre
对象传递给该组件。
useGame
模板又将接收到的查询参数对象传递给 useData
组件
useData
模板在发送 GET 请求时将配置请求使用扩展运算符带上,同时给 useEffect
提供一个可选参数,用于决定是否触发重新渲染
useGame
组件内在 useData
组件上添加上该依赖数组,即 selectedGenre.id
graph TD
A[App] -->|state: selectedGenre| B[GenreList]
A -->|prop: selectedGenre| C[GameGrid]
B -->|prop: onSelectGenre| D[Genre Items]
D -->|"onClick: onSelectGenre(genre)"| B
B -->|"setSelectedGenre(genre)"| A
C -->|prop: selectedGenre| E[useGames Hook]
E -->|param: selectedGenre| F[useData Hook]
F -->|request param| G[API Request]
F -->|response data| E
E -->|games data| C
H[useEffect] -->|dependency: selectedGenre.id| F
Highlight the Selected Genre
在 GenreList
组件内根据传递的 genre.id
是否等于 selectedGenre.id
来作判断决定 fontWeight
是 bold
还是 normal
。
需要在 App
组件内传递 selectedGenre
作为 Props
App.tsx 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import { Grid, GridItem, Show } from "@chakra-ui/react";
import NavBar from "./components/NavBar";
import GameGrid from "./components/GameGrid";
import GenreList from "./components/GenreList";
import { useState } from "react";
import { Genre } from "./hooks/useGenres";
function App() {
const [selectedGenre, setSelectedGenre] = useState<Genre | null>(null);
return (
<Grid
templateAreas={{
base: `"nav" "main"`,
lg: `"nav nav" "aside main"`,
}}
templateColumns={{
base: "1fr",
lg: "250px 1fr",
}}
>
<GridItem area="nav">
<NavBar />
</GridItem>
<Show above="lg">
<GridItem area="aside" paddingX={5}>
<GenreList
onSelectGenre={(genre) => setSelectedGenre(genre)}
selectedGenre={selectedGenre}
/>
</GridItem>
</Show>
<GridItem area="main">
<GameGrid selectedGenre={selectedGenre} />
</GridItem>
</Grid>
);
}
export default App;
GenreList.tsx 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 import {
List,
ListItem,
HStack,
Image,
Spinner,
Button,
} from "@chakra-ui/react";
import useGenres, { Genre } from "../hooks/useGenres";
import getCroppedImageUrl from "../services/image-url";
interface Props {
onSelectGenre: (genre: Genre) => void;
selectedGenre: Genre | null;
}
const GenreList = ({ onSelectGenre, selectedGenre }: Props) => {
const { data, isLoading, error } = useGenres();
if (error) return null;
if (isLoading) return <Spinner />;
return (
<List>
{data.map((genre) => (
<ListItem key={genre.id} paddingY="5px">
<HStack>
<Image
boxSize="32px"
borderRadius={8}
src={getCroppedImageUrl(genre.image_background)}
></Image>
<Button
fontWeight={genre.id == selectedGenre?.id ? "bold" : "normal"}
onClick={() => onSelectGenre(genre)}
variant="link"
>
{genre.name}
</Button>
</HStack>
</ListItem>
))}
</List>
);
};
export default GenreList;
首先调接口,拿到 platforms
的数据,然后新建一个组件,展示数据,最后添加到 App
组件。
usePlatforms.tsx import useData from "./useData";
export interface Platform {
id: number;
name: string;
slug: string;
}
const usePlatforms = () => useData<Platform>("/platforms/lists/parents");
export default usePlatforms;
PlatformSelector.tsx 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import { Button, Menu, MenuButton, MenuItem, MenuList } from "@chakra-ui/react";
import { BsChevronDown } from "react-icons/bs";
import usePlatforms from "../hooks/usePlatforms";
const PlatfromSelector = () => {
const { data, error } = usePlatforms();
if (error) return null;
return (
<Menu>
<MenuButton as={Button} rightIcon={<BsChevronDown />}>
PlatFroms
</MenuButton>
<MenuList>
{data.map((platform) => (
<MenuItem key={platform.id}>{platform.name}</MenuItem>
))}
</MenuList>
</Menu>
);
};
export default PlatfromSelector;
App.tsx 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import { Grid, GridItem, Menu, Show } from "@chakra-ui/react";
import NavBar from "./components/NavBar";
import GameGrid from "./components/GameGrid";
import GenreList from "./components/GenreList";
import { useState } from "react";
import { Genre } from "./hooks/useGenres";
import PlatfromSelector from "./components/PlatfromSelector";
function App() {
const [selectedGenre, setSelectedGenre] = useState<Genre | null>(null);
...
</GridItem>
</Show>
<GridItem area="main">
<PlatfromSelector />
<GameGrid selectedGenre={selectedGenre} />
</GridItem>
</Grid>
跟筛选分类一样的步骤
App
传递一个名为匿名回调函数(() => setSelectedPlatform(Platform)
)给 PlatformSelector
组件的 onSelectPlatform
Prop,用于告知 App
哪个平台被选中。
当用户点击子组件的某个列表项时,回调函数被触发,并将对应的 Platform
传递给父组件 (onClick={() => onSelectPlatform(platform)
)。
同时把 selectedPlatform
作为 Prop 传给自己用来回显名称,同时,还要作为 Prop 传给 GameGrid
,GameGrid
再把该 Props 传给 UseGame
请求接口数据,在 UseGame
内,新增查询参数 selectedPlatform
,并在依赖数组中添加其 id 用于数据更新时触发组件重新渲染
2024-08-17 01:35 2024-08-18 17:19