两种组件间通信方式
使用Context进行组件通信
创建context
文件夹,并创建menuContext
文件,用于创建上下文。
tsx
import React from 'react'
export const menuContext = React.createContext({
setVisible: (visible: boolean) => {}
})
修改Icon.tsx
组件,使其接受点击事件。
tsx
import c from 'classnames'
import React from 'react'
interface Props {
className?: string
name: string
onClick?: (e: React.MouseEvent) => void
}
export const Icon: React.FC<Props> = ({ name, className, onClick }) => {
return (
<svg className={c(className, 'j-icon')} onClick={onClick}>
<use xlinkHref={`#${name}`}></use>
</svg>
)
}
创建TopMenu.tsx
文件
tsx
export const TopMenu: React.FC = () => {
return (
<div fixed top-0 left-0 bg-red>TopMenu </div>
)
}
然后在ItemsPages.tsx
文件中使用menuContext
上下文进行注入。
tsx
import styled from 'styled-components'
import { useState } from 'react'
import { AddItemFloatButton } from '../components/AddItemFloatButton'
import { TimeRangePicker } from '../components/TimeRangePicker'
import type { TimeRange } from '../components/TimeRangePicker'
import { TopNav } from '../components/TopNav'
import { menuContext } from '../context/menuContext'
import { TopMenu } from '../components/TopMenu'
import { ItemsList } from './ItemsPage/ItemsList'
import { ItemsSummary } from './ItemsPage/ItemsSummary'
const Div = styled.div`
background: linear-gradient(0deg, rgba(143,76,215,1) 0%, rgba(92,51,190,1) 100%);
`
export const ItemsPage: React.FC = () => {
const [timeRange, setTimeRange] = useState<TimeRange>('thisMonth')
const [items] = useState<Item[]>([
{
id: 1,
kind: 'incomes',
amount: 1000,
user_id: 1,
tag_ids: [1],
happen_at: '2021-01-01T00:00:00.000Z',
created_at: '2021-01-01T00:00:00.000Z',
updated_at: '2021-01-01T00:00:00.000Z',
}, {
id: 2,
kind: 'incomes',
amount: 1000,
user_id: 1,
tag_ids: [1],
happen_at: '2021-01-01T00:00:00.000Z',
created_at: '2021-01-01T00:00:00.000Z',
updated_at: '2021-01-01T00:00:00.000Z',
}
])
const [visible, setVisible] = useState(false)
return (
<div>
<menuContext.Provider value={{ setVisible }}>
<Div>
<TopNav />
<TimeRangePicker selected={timeRange} onSelected={setTimeRange} />
</Div>
<ItemsSummary />
<ItemsList items={items}/>
<AddItemFloatButton />
{visible ? <TopMenu /> : null}
</menuContext.Provider>
</div>
)
}
然后在TopNav.tsx
中使用useContext接受menuContext
对象,修改visble
的值。
tsx
import { useContext } from 'react'
import { menuContext } from '../context/menuContext'
import { Icon } from './Icon'
interface Props {
title?: string
}
export const TopNav: React.FC<Props> = ({ title = '山竹记账' }) => {
const { setVisible } = useContext(menuContext)
return (
<div text-white flex items-center pt-24px pb-8px px-24px>
<Icon name="menu" className="w-24px h-24px mr-16px"
onClick={ () => { setVisible(true) }} />
<h1 text-24px>{title}</h1>
</div>
)
}
使用zustand进行组件通信
使用zustand数据状态管理来进行组件之间的通信,详细代码见链接。
封装useMenuStore
tsx
import create from 'zustand'
interface Menu {
visible: boolean
setVisible: (visible: boolean) => void
}
export const useMenuStore = create<Menu>((set, get) => ({
visible: false,
setVisible: (visible) => {
set({ visible })
}
}))
然后在ItemsPages.tsx
文件中使用useMenuStore
的visible
的值。
tsx
import styled from 'styled-components'
import { useState } from 'react'
import { AddItemFloatButton } from '../components/AddItemFloatButton'
import { TimeRangePicker } from '../components/TimeRangePicker'
import type { TimeRange } from '../components/TimeRangePicker'
import { TopNav } from '../components/TopNav'
import { TopMenu } from '../components/TopMenu'
import { useMenuStore } from '../stores/useMenuStore'
import { ItemsList } from './ItemsPage/ItemsList'
import { ItemsSummary } from './ItemsPage/ItemsSummary'
const Div = styled.div`
background: linear-gradient(0deg, rgba(143,76,215,1) 0%, rgba(92,51,190,1) 100%);
`
export const ItemsPage: React.FC = () => {
const [timeRange, setTimeRange] = useState<TimeRange>('thisMonth')
const [items] = useState<Item[]>([
{
id: 1,
kind: 'incomes',
amount: 1000,
user_id: 1,
tag_ids: [1],
happen_at: '2021-01-01T00:00:00.000Z',
created_at: '2021-01-01T00:00:00.000Z',
updated_at: '2021-01-01T00:00:00.000Z',
}, {
id: 2,
kind: 'incomes',
amount: 1000,
user_id: 1,
tag_ids: [1],
happen_at: '2021-01-01T00:00:00.000Z',
created_at: '2021-01-01T00:00:00.000Z',
updated_at: '2021-01-01T00:00:00.000Z',
}
])
const { visible } = useMenuStore()
return (
<div>
<Div>
<TopNav />
<TimeRangePicker selected={timeRange} onSelected={setTimeRange} />
</Div>
<ItemsSummary />
<ItemsList items={items}/>
<AddItemFloatButton />
{visible ? <TopMenu /> : null}
</div>
)
}
并在TopNav.tsx
中使用useMenuStore
的setVisible
方法修改visible
的值。
tsx
import { useMenuStore } from '../stores/useMenuStore'
import { Icon } from './Icon'
interface Props {
title?: string
}
export const TopNav: React.FC<Props> = ({ title = '山竹记账' }) => {
const { visible, setVisible } = useMenuStore()
return (
<div text-white flex items-center pt-24px pb-8px px-24px>
<Icon name="menu" className="w-24px h-24px mr-16px"
onClick={ () => setVisible(!visible) } />
<h1 text-24px>{title}</h1>
</div>
)
}