【山竹记账前端-react】12.两种组件间通信的方式


大纲链接 §

[toc]


1. 组件化有利有弊 ⇧

组件化的缺点

  • 使得每个组件模块自成一体,需要额外通信交流
  • 一个组件需要触发另一个组件的某个执行逻辑
  • 仅关心自身的输入输出,需要第三方工具

组件通信第三方工具

  • context 较麻烦
  • zustand

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 ⇧

``

1


4. 小结 ⇧

两种组件间通信的方式


5. $3 ⇧


6. $3 ⇧


·未完待续·

参考文章

相关文章

  • 无

  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名