【山竹记账前端-react】12.两种组件间通信的方式
大纲链接 §
[toc]
1. 组件化有利有弊 ⇧
组件化的缺点
- 使得每个组件模块自成一体,需要额外通信交流
- 一个组件需要触发另一个组件的某个执行逻辑
- 仅关心自身的输入输出,需要第三方工具
组件通信第三方工具
2. 使用Context进行组件通信 ⇧
以制作一个右滑浮动遮罩菜单为例 FloatingOverlayMenu.tsx
- 需要在
TopNav 组件中的按钮点击后,展示 FloatingOverlayMenu 的菜单
- 创建上下文
const MenuContext = React.createContext({ setVisible: () => {} })
- 划定范围,哪些组件可以使用这个上下文
<MenuContext.Provider>{/* 这个标签框住的范围就是提供上下文数据的范围 */}</MenuContext.Provider>
- 提供默认值
<MenuContext.Provider value={{ setVisible: setMenuVisible }} >
- 只要处于上下文范围中的组件都可以拿到这个值
setVisible
- 上下文就等于全部的全局变量;全局变量 === 全局的上下文
- 导出这个上下文
export const MenuContext = ...
- 在子孙组件
TopNav 中引入 const x = useContext(MenuContext)
- 需要引入
import { useContext } from "react"
- 可解构
const { setVisible } = useContext(MenuContext)
- 使用了循环引用
TopNav 引用了 ItemsPage 的 MenuContext;ItemsPage 引用了 TopNav
- 虽然引用的不是一个变量,但不推荐使用循环引用
- 也可以将
MenuContext 放到第三方文件中,解除循环引用
@/pages/ItemsPage.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
|
import { AddItemFloatButton } from "@/components/AddItemFloatButton"
import { DateRangePicker, DateTabRangeStr } from "@/components/DateRangePicker"
import { FloatingOverlayMenu } from "@/components/FloatingOverlayMenu"
import { TopNav } from "@/components/TopNav"
import { ItemsSummary } from "@/modules/items/ItemsSummary"
import { cn } from "cn"
import React from "react"
import { useState } from "react"
export const MenuContext = React.createContext({ setVisible: (visible: boolean) => { } })
export const ItemsPage: React.FC = () => {
const [selectedDate, setSelectedDate] = useState<DateTabRangeStr>('thisMonth')
const [menuVisible, setMenuVisible] = useState(false)
return (
<div>
<MenuContext.Provider value={{ setVisible: setMenuVisible }} >
<header
className={cn(
'bg-linear-to-b from-[var(--welcome-card-start)] to-[var(--welcome-card-end)]',
)}>
<TopNav />
<DateRangePicker selectedId={selectedDate} onSelected={setSelectedDate} />
</header>
<ItemsSummary startDate={selectedDate} endDate={selectedDate} />
<AddItemFloatButton />
{ menuVisible && <FloatingOverlayMenu /> }
</MenuContext.Provider>
</div>
)
}
|
@/components/TopNav.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import { SvgIcon } from "@/components/SvgIcon"
import { MenuContext } from "@/pages/ItemsPage"
import { cn } from "cn"
import { useContext } from "react"
interface Props {
title?: string
className?: string
}
export const TopNav: React.FC<Props> = ({ title = '山竹记账', className }) => {
const { setVisible } = useContext(MenuContext)
return (
<div
className={cn(
'h-64px pt-24px pb-.5em px-24px text-white flex items-center gap-x-1em',
className,
)}>
<SvgIcon name="menu" className="size-[2em]" onClick={() => setVisible(true)} />
<h1 className="text-[2em]">{title}</h1>
</div>
)
}
|
3. 使用zustand进行组件通信,封装useMenuStore ⇧
``
4. 小结 ⇧

5. $3 ⇧
6. $3 ⇧
·未完待续·
参考文章
相关文章
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名