前言
在此之前,曾经写过两篇关于组件嵌套关系的组件文章:
搞轮子:从业务到组件Tabs
搞轮子:TabBar标签栏的自救
Tabs 组件首次使用 React.Children.map 来”解构“子组件,释放子组件写法
1 2 3 4 5 6
| <Tabs value={value} swipeable> <Tabs.Panel title="标签1">内容 1</Tabs.Panel> <Tabs.Panel title="标签2">内容 2</Tabs.Panel> <Tabs.Panel title="标签3">内容 3</Tabs.Panel> <Tabs.Panel title="标签4">内容 4</Tabs.Panel> </Tabs>
|
TabBar 组件再次基础上,又使用了 React.cloneElement,使组件的状态变化由父组件提供
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <TabBar activeKey={activeKey} onChange={(key: any) => { setActiveKey(key); }} > <TabBar.Item itemKey="home" title="主页" icon={<IconTabbarHome />} /> <TabBar.Item itemKey="financial" title="理财" icon={<IconTabbarFinancial />} /> <TabBar.Item itemKey="user" title="我的" icon={<IconTabbarUser />} /> </TabBar>
|
TabBar 是底部的菜单栏,有选中和非选择两种状态,所以要给父组件设置”当前选中项“,每个子组件设置唯一标识符,这样才能判断那个元素被选中了
而今天说的 SortBar 状态变为三种,分别为未选择,降序、升序
正文
我们要做成什么样子呢?如下图所示:

有筛选、和三个有状态的子组件。其实和 TabBar 组件很像,无非是多了筛选组件,把两种状态改为三种
先看书写结构:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <SortBar activeKey={activeKey} onChange={(key: string, status: string) => { setActiveKey(key); }} onClick={() => { console.log('点击筛选'); }} > <SortBar.Item title="年化" itemKey="annualized" /> <SortBar.Item title="期限" itemKey="term" /> <SortBar.Item title="价格" itemKey="price" /> </SortBar>
|
和 TabBar 可以说一摸一样,其中 onClick
是针对点击筛选组件的,其核心思路和 TabBar一样,核心代码是:
1 2 3 4 5 6 7 8 9 10 11 12
| const items = React.Children.map(children, (element, index) => { if (!React.isValidElement(element)) return null;
return cloneElement(element, { key: index, title: element.props.title, itemKey: element.props.itemKey || index, selected: activeKey === element.props.itemKey, onClick: (status: string) => onHandleClick(element.props.itemKey, status), }); });
|
React.Children 遍历子元素
React.isValidElement 判断子元素是否是 React 元素
cloneElement 在原来的子组件上添加其他元素
- selected:新添加的元素,判断当前选中key和自身的 key 是否是同一个
- onClick:点击的时候哪个key,什么status(状态)传给父元素,好让父元素做业务处理
选中和未选中此子组件由父组件控制,而选中此子组件的状态则在子组件中完成,请看代码:
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
| const Item: FC<SortBarItemProps> = (props) => { const { title, selected, onClick } = props; const [status, setStatus] = useState('0');
useEffect(() => { if (selected === false) { setStatus('0'); } }, [selected]);
const onHandleClick = () => { if (status === '0' || status === '2') { setStatus('1'); onClick && onClick('1'); } else if (status === '1') { setStatus('2'); onClick && onClick('2'); } };
return ( <div className={`${prefixCls}`} onClick={onHandleClick}> {title} {status === '0' && <IconFilterEmty size="sm" />} {status === '1' && <IconFilterDown size="sm" />} {status === '2' && <IconFilterUp size="sm" />} </div> ); };
|
默认为都未选择,当点击后改变状态。
总结
这一些告一段落,已经没什么好讲的了