之前的工作经验中,始终都是应用 Antd 作为根底组件进行开发,当初咱们要本人实现一套治理后盾的 UI 组件库,在写到 Tabs 这个组件的时候借鉴了 Antd 的思路,次要用到了 React Context 个性,在此记录下

次要展示外围思路(仅实现受控组件),款式细节略过,效果图如下

  • 应用形式

    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>
  • 组件导出模块,实现 <Tabs.Panel></Tabs.Panel> 这种模式应用

    // 模拟 antd 实现 https://github.com/ant-design/ant-design/blob/master/components/radio/index.tsximport TabsComps, { TTabsProp } from './Tabs'import Panel from './Panel'interface CompoundedComponent  extends React.ForwardRefExoticComponent<    TTabsProp & React.RefAttributes<HTMLElement>  > {  Panel: typeof Panel}const Tabs = TabsComps as CompoundedComponentTabs.Panel = Panelexport default Tabs
  • context 实现

    import React from 'react'const TabsContext = React.createContext<any>(null)export default TabsContext
  • Panel 组件实现

    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 实现

    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>    </>  )}