In the previous work experience, we have always used Antd as the basic component for development. Now we have to implement a UI component library for managing the background. When writing the Tabs component, we borrowed the ideas of Antd, mainly using React Context characteristics, documented here
It mainly shows the core idea (only the controlled components are implemented), and the style details are skipped. The renderings are as follows
How to use
const [value, setValue] = useState('1') <Tabs activeKey={value} isCache={true} onChange={value => setValue(value)} > <Tabs.Panel tabKey='1' tab='Tab Item'><div>11111</div></Tabs.Panel> <Tabs.Panel tabKey='1' tab='Tab Item'><div>11111</div></Tabs.Panel> </Tabs>
Component export module, implementation
<Tabs.Panel></Tabs.Panel>
use this form// 模仿 antd 实现 https://github.com/ant-design/ant-design/blob/master/components/radio/index.tsx import TabsComps, { TTabsProp } from './Tabs' import Panel from './Panel' interface CompoundedComponent extends React.ForwardRefExoticComponent< TTabsProp & React.RefAttributes<HTMLElement> > { Panel: typeof Panel } const Tabs = TabsComps as CompoundedComponent Tabs.Panel = Panel export default Tabs
context implementation
import React from 'react' const TabsContext = React.createContext<any>(null) export default TabsContext
Panel component implementation
import { ReactElement, useContext } from 'react' import cn from 'classnames' import TabsContext from './context' export type TPanelProp = { tab: string | ReactElement tabKey: string | number } // 此处需要注意的是 Tab.Panel 的 children 属性交由 Tabs 组件处理 export default function Panel({ tab, tabKey }: TPanelProp): JSX.Element { const tabCtx = useContext(TabsContext) return ( <div className={cn(tabCtx.activeKey === tabKey ? 'active' : '')} onClick={() => tabCtx.onChange(tabKey)} > {tab} </div> ) }
Tabs implementation
import { ReactElement } from 'react' import cn from 'classnames' import TabsContext from './context' export type TTabsProp = { isCache?: boolean // 是否用 display 隐藏元素 children: ReactElement[] activeKey: string | number onChange?: (value: any) => void } export default function Tabs({ isCache = true, children, activeKey, onChange, }: TTabsProp): JSX.Element { let panel = null if (isCache) { panel = children?.map(v => { const tabKey = v.props.tabKey return ( <div key={tabKey} className={tabKey === activeKey ? '' : 'hidden'}> {v.props.children} </div> ) }) } else { panel = children.find(v => v.props?.tabKey === activeKey)?.props?.children } return ( <> <div> <TabsContext.Provider value={{ activeKey, onChange }}> {children} </TabsContext.Provider> </div> <div>{panel}</div> </> ) }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。