🎶 Sym - 一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)平台

📕 思源笔记 - 一款桌面端笔记应用,支持 Windows、Mac 和 Linux

🎸 Solo - B3log 分布式社区的博客端节点,欢迎加入下一代社区网络

♏ Vditor - 一款浏览器端的 Markdown 编辑器

React Visual - 手风琴 (advanced)

2019-09-23

描述

渲染一个包含多个可折叠内容组件的手风琴菜单。

  • 定义一个 AccordionItem 组件,并将其传递给 Accordion。除了在 props.children 中函数名称标识为 AccordionItem 的节点外移除其余不必要的节点
  • 每一个 AccordionItem 组件都渲染一个 <button>,通过 props.handleClick 回调和传递到组件中的内容 props.children 来更新 Accordion。他们的展现通过 props.isCollapsed 及对应的 style 来确定
  • Accordion 组件中,使用 React.useState() hook 来初始化状态变量 bindIndex 的默认值为 props.defaultIndex
  • 在过滤出的节点中使用 Array.prototype.map 来渲染每一个可折叠的元素
  • 定义 changeItem 方法,在点击 AccordionItem 中的 <button> 时将会被执行。changeItem 执行传递的回调函数 onItemClick 并更新 bindIndex 为被点击元素的 index 属性值

实现

function AccordionItem(props) {
  const style = {
    collapsed: {
      display: 'none'
    },
    expanded: {
      display: 'block'
    },
    buttonStyle: {
      display: 'block',
      width: '100%'
    }
  };

  return (
    <div>
      <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>
  );
}

function Accordion(props) {
  const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);

  const changeItem = itemIndex => {
    if (typeof props.onItemClick === 'function') props.onItemClick(itemIndex);
    if (itemIndex !== bindIndex) setBindIndex(itemIndex);
  };
  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>
  );
}

使用

ReactDOM.render(
  <Accordion defaultIndex="1" onItemClick={console.log}>
    <AccordionItem label="A" index="1">
      Lorem ipsum
    </AccordionItem>
    <AccordionItem label="B" index="2">
      Dolor sit amet
    </AccordionItem>
  </Accordion>,
  document.getElementById('root')
);

返回总目录

每天 30 秒系列之 React


欢迎注册黑客派社区,开启你的博客之旅。让学习和分享成为一种习惯!

推荐阅读
留下你的脚步