React 30 秒速学:制作手风琴组件

4,321 阅读1分钟

本文译自: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>
  );
}