本文同时发布于掘金,地址:https://juejin.im/post/6844903849891725319
本文译自:30-seconds-of-react。React 30 秒速学:全篇中文翻译、学习,地址:30-seconds-of-react-zh_CN-umi,所有案例进行分析、注释、上线。
手风琴组件
手风琴效果组件,包含多个可折叠内容。
- 定义一个
AccordionItem
组件,将它传递给Accordion
。并通过在props.children
中识别函数的名称来删除AccordionItem
所需的不必要的节点。 - 每个
AccordionItem
组有一个<button>
,用于通过props.handleClick
回调更新Accordion
和组件的内容,通过props.children
向下传递,它的折叠状态由props.isCollapsed
确定。 - 在
Accordion
组件中,使用React.useState()
钩子将bindIndex
状态变量的值初始化为props.defaultIndex
。 - 在收集的节点上使用
Array.prototype.map
来渲染单个可折叠的元素。 - 定义
changeItem
,它将在单击AccordionItem
的<button>
时执行。changeItem
执行传递的回调,onItemClick
并根据点击的元素更新bindIndex
。
AccordionItem 组件:
import React from "react";
function AccordionItem(props) {
const style = {
collapsed: {
display: "none"
},
expanded: {
display: "block"
},
buttonStyle: {
display: "block",
width: "100%"
}
};
return (
<div>
{/* 按钮,点击传入的 handleClick */}
<button style={style.buttonStyle} onClick={() => props.handleClick()}>
{props.label}
</button>
{/* 控制显示、隐藏状态 */}
<div
className="collapse-content"
style={props.isCollapsed ? style.collapsed : style.expanded}
aria-expanded={props.isCollapsed}
>
{/* 内容 */}
{props.children}
</div>
</div>
);
}
Accordion 组件:
function Accordion(props) {
// 目前显示的 index
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
// 点击即把 bindIndex 设置为自己
const changeItem = itemIndex => {
if (typeof props.onItemClick === "function") props.onItemClick(itemIndex);
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
};
// 筛选出传入的 AccordionItem 组件,忽略其他
const items = props.children.filter(
// 组件名
item => item.type.name === "AccordionItem"
);
return (
<div className="wrapper">
{items.map(({ props }) => (
<AccordionItem
isCollapsed={bindIndex === props.index}
label={props.label}
handleClick={() => changeItem(props.index)}
children={props.children}
/>
))}
</div>
);
}
例子
export default function() {
return (
<Accordion defaultIndex="1" onItemClick={console.log}>
<AccordionItem label="A" index="1">
Lorem ipsum
</AccordionItem>
<AccordionItem label="B" index="2">
Dolor sit amet
</AccordionItem>
</Accordion>
);
}