Show/Hide 每个按钮的多个元素点击与 React JS 中的匹配索引

Show/Hide multiple elements of each button click with matching indexes in React JS

我有一个场景,其中有 2 个不同的组件(按钮和信息容器)。在每个按钮上单击我试图显示每个匹配的信息容器。我能够在我的按钮中实现所需的功能,但是当我将状态传回我的其他组件时,我只能显示匹配的索引。我想要的结果是,如果我单击导航中的一个按钮并且它有一个活动的 class,我的所有“信息容器”应该保持可见,直到“活动”class 为 toggled/removed。

JS:

...

const useStyles = makeStyles((theme) => ({
  root: {
    display: "flex",
    "& > *": {
      margin: theme.spacing(1)
    }
  },
  orange: {
    color: theme.palette.getContrastText(deepOrange[500]),
    backgroundColor: deepOrange[500],
    border: "4px solid black"
  },
  info: {
    margin: "10px"
  },
  wrapper: {
    display: "flex"
  },
  contentWrapper: {
    display: "flex",
    flexDirection: "column"
  },
  elWrapper: {
    opacity: 0,
    "&.active": {
      opacity: 1
    }
  }
}));

const ToggleItem = ({ onChange, id, styles, discription }) => {
  const [toggleThisButton, setToggleThisButton] = useState(false);

  const handleClick = (index) => {
    setToggleThisButton((prev) => !prev);
    onChange(index);
  };

  return (
    <>
      <Avatar
        className={toggleThisButton ? styles.orange : ""}
        onClick={() => handleClick(id)}
      >
        {id}
      </Avatar>
      {JSON.stringify(toggleThisButton)}
      {/* {toggleThisButton && <div className={styles.info}>{discription}</div> } */}
    </>
  );
};

const ToggleContainer = ({ discription, className }) => {
  return <div className={className}> Content {discription}</div>;
};

export default function App() {
  const data = ["first", "second", "third"];
  const classes = useStyles();
  const [value, setValue] = useState(false);

  const handleChange = (newValue) => {
    setValue(newValue);
    console.log("newValue===", newValue);
  };

  return (
    <>
      <div className={classes.wrapper}>
        {data.map((d, id) => {
          return (
            <div key={id}>
              <ToggleItem
                id={id}
                styles={classes}
                discription={d}
                onChange={handleChange}
              />
            </div>
          );
        })}
      </div>
      <div className={classes.contentWrapper}>
        {data.map((d, id) => {
          return (
            <ToggleContainer
              className={
                value === id
                  ? clsx(classes.elWrapper, "active")
                  : classes.elWrapper
              }
              key={id}
              styles={classes}
              discription="Hello"
            />
          );
        })}
      </div>
    </>
  );
}
 

Codesanbox: https://codesandbox.io/s/pedantic-dream-vnbgym?file=/src/App.js:0-2499

Codesandbox : https://codesandbox.io/s/72166087-zu4ev7?file=/src/App.js

您可以将选定的选项卡存储在一个状态中。这样你就不需要渲染 3(或更多)<ToggleContainer>。在 <ToggleContainer> 中将选定的选项卡作为道具传递并在 <ToggleContainer> 中呈现选定的选项卡内容。

import React, { useState } from "react";
import "./styles.css";
import { makeStyles } from "@material-ui/core/styles";
import Avatar from "@material-ui/core/Avatar";
import { deepOrange } from "@material-ui/core/colors";
import clsx from "clsx";

const useStyles = makeStyles((theme) => ({
  root: {
    display: "flex",
    "& > *": {
      margin: theme.spacing(1)
    }
  },
  orange: {
    color: theme.palette.getContrastText(deepOrange[500]),
    backgroundColor: deepOrange[500],
    border: "4px solid black"
  },
  info: {
    margin: "10px"
  },
  wrapper: {
    display: "flex"
  },
  contentWrapper: {
    display: "flex",
    flexDirection: "column"
  },
  elWrapper: {
    opacity: 0,
    "&.active": {
      opacity: 1
    }
  }
}));

const ToggleItem = ({ onChange, id, styles, discription }) => {
  const [toggleThisButton, setToggleThisButton] = useState(false);

  const handleClick = (index) => {
    onChange(discription, !toggleThisButton);
    setToggleThisButton((prev) => !prev);
  };

  return (
    <>
      <Avatar
        className={toggleThisButton ? styles.orange : ""}
        onClick={() => handleClick(id)}
      >
        {id}
      </Avatar>
      {JSON.stringify(toggleThisButton)}
      {/* {toggleThisButton && <div className={styles.info}>{discription}</div> } */}
    </>
  );
};

const ToggleContainer = ({ className, selected }) => {
  return (
    <div className={className}>
      {selected.map((item, idx) => (
        <div key={idx}>Content {item}</div>
      ))}
    </div>
  );
};

export default function App() {
  const data = ["first", "second", "third"];
  const classes = useStyles();
  const [selected, setSelected] = useState([]);

  // action : False -> Remove, True -> Add
  const handleChange = (val, action) => {
    let newVal = [];
    if (action) {
      // If toggle on, add content in selected state
      newVal = [...selected, val];
    } else {
      // If toggle off, then remove content from selected state
      newVal = selected.filter((v) => v !== val);
    }
    console.log(newVal);
    setSelected(newVal);
  };

  return (
    <>
      <div className={classes.wrapper}>
        {data.map((d, id) => {
          return (
            <div key={id}>
              <ToggleItem
                id={id}
                styles={classes}
                discription={d}
                onChange={handleChange}
              />
            </div>
          );
        })}
      </div>
      <div className={classes.contentWrapper}>
        <ToggleContainer styles={classes} selected={selected} />
      </div>
    </>
  );
}