跳转至

Filtering Games

  1. GenreList 模板声明一个新接口 onSelectGenre,该参数用于告知分类已经被选中,
  2. App 组件获得通知,给 GenreList 组件设置 setSelectedGenre,并把设置后的值 selectedGenreGameGrid 组件触发渲染。
  3. GameGrid 模板内,接收到 selectedGenre 对象,该对象作为查询参数用来传递给后端接口请求数据,所以又涉及到 useGame 组件,将 selectedGenre 对象传递给该组件。
  4. useGame 模板又将接收到的查询参数对象传递给 useData 组件
  5. useData 模板在发送 GET 请求时将配置请求使用扩展运算符带上,同时给 useEffect 提供一个可选参数,用于决定是否触发重新渲染
  6. 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 来作判断决定 fontWeightbold 还是 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;

Build Platform Selector#

首先调接口,拿到 platforms 的数据,然后新建一个组件,展示数据,最后添加到 App 组件。

usePlatforms.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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>

Filter Games by Platform#

跟筛选分类一样的步骤

App 传递一个名为匿名回调函数(() => setSelectedPlatform(Platform))给 PlatformSelector 组件的 onSelectPlatform Prop,用于告知 App 哪个平台被选中。

当用户点击子组件的某个列表项时,回调函数被触发,并将对应的 Platform 传递给父组件 (onClick={() => onSelectPlatform(platform))。

同时把 selectedPlatform 作为 Prop 传给自己用来回显名称,同时,还要作为 Prop 传给 GameGridGameGrid 再把该 Props 传给 UseGame 请求接口数据,在 UseGame 内,新增查询参数 selectedPlatform,并在依赖数组中添加其 id 用于数据更新时触发组件重新渲染

2024-08-17 01:35 2024-08-18 17:19

评论