如何使用 refs 控制兄弟元素的行为?

How to control sibling elements' behaviour with refs?

我有 Modal 个带有信息框的组件。在每个 InfoBox 中,一个按钮(图标)显示有关产品特定成分的更多信息。该功能包含在每个 InfoBox 组件中。

当您单击一个信息框中的按钮(图标)时,我希望关闭所有其他信息框 - 如何使用 refs 控制同级元素的行为?

我正在尝试:

  1. 向下传递一个函数给每个信息框
  2. 当单击一个框时,发送该事件最多 parent 个元素(模态)
  3. 然后在 parent 元素中,遍历 refs 数组,找到图标被点击的那个,然后通过 useImperativeHandle 调用所有其他 refs 中的 closeShowMore 函数.

但我不知道如何在点击按钮的 refarray 中标记那个特定的 ref。

提前感谢您的宝贵时间!

PARENT:

const Modal = forwardRef(({ beer }, ref) => {
  // stuff removed for brev
  
  const [infoRef, setInfoRef] = useState([]);

  const closeInfoBox = (valuePassedfromChildsEvent) => {
    // here I would loop through infoRef, find the ref in which the button was clicked and then close the rest through useImperativeHandle()
  };

  useEffect(() => {
    // create an array of refs for infoBoxes
    setInfoRef(
      Array(6)
        .fill()
        .map((_, i) => infoRef[i] || createRef())
    );
  }, []);

  if (display) {
    return (
      <div className="modal-wrapper">
        <div ref={backgroundRef} className="modal-background"></div>
        <div className="modal-box">
          <div className="info-box-wrapper">
            <InfoBox
              ref={infoRef[0]}
              name="abv"
              value={abv}
              imageUrl={"../../assets/abv-white-2.svg"}
              showMoreActive={closeInfoBox}
            />
            <InfoBox
              ref={infoRef[1]}
              name="ibu"
              value={ibu}
              imageUrl={"../../assets/ibu-white.svg"}
              showMoreActive={closeInfoBox}
            />
            <InfoBox
              ref={infoRef[2]}
              name="fg"
              value={target_fg}
              imageUrl={"../../assets/style-white.svg"}
              showMoreActive={closeInfoBox}
            />
           // a few more of these 
          </div>
        </div>
      </div>
    );
  }
  return null;
});

export default Modal;

CHILD:

const InfoBox = forwardRef((props, ref) => {
  const [showMore, setShowMore] = useState(false);
  const { name, value, imageUrl, showMoreActive } = props;

  useImperativeHandle(ref, () => ({
    openShowMore,
    closeShowMore,
    // is there a way to add an 'isActive' state/var here so I can access this from the loop in the parent and say if(!infoRef.current.isActive) {closeShowMore()}?
  }));

  const openShowMore = () => {
    setShowMore(true);
    showMoreActive(showMore) // I tried sending up this state value to parent to mark the active child but this always logs false when passed to parent, even when true. why?
  };

  const closeShowMore = () => {
    setShowMore(false);
  };

  return (
    <div className={`${name}`}>
      <div className="info-box-container">
        <div className="info-box-container-top">
          <img src={imageUrl} alt="icon" />
          <div className="info-wrapper">
            <h4>{name}</h4>
            <h5>{value}</h5>
          </div>
          <div
            className="plus-minus-icon-wrapper"
            onClick={() => openShowMore()}
          >
            {!showMore ? <GoPlus /> : <FiMinus />}
          </div>
        </div>
        {showMore && (
          <div className="info-box-conetiner-bottom">
            <p>
              Lorem ipsum dolor sit amet consectetur adipisicing elit. Officia
              optio ab ullam! Porro molestias accusantium et laborum distinctio
            </p>
          </div>
        )}
      </div>
    </div>
  );
});

export default InfoBox;

你把它变得不必要地复杂了。 您想要的是使用尽可能少的状态,并将该状态保留在所有受影响组件的最小公共父级中。

在你的情况下,你想要做的是在 Modal 中有一个状态变量,它是这样的:

const [expandedInfoBoxName, setExpandedInfoBoxName] = useState(null);

您将这些道具传递给您的 InfoBox:

<InfoBox
    name="ibu"
    {your other props}
    expandInfoBox={() => setExpandedInfoBoxName("ibu")
    showMore={expandedInfoBoxName === "ibu"}
/>

在您的信息框中,您删除了状态和函数 useImperativeHandle、openShowMore 和 closeShowMore。 添加此以获得您的新道具:

const { name, value, imageUrl, expandInfoBox, showMore } = props;

然后在你的 jsx 中你做:

<div
   className="plus-minus-icon-wrapper"
   onClick={expandInfoBox}
>

就是这样。简而言之,您不想分散您的状态。总是问自己描述某事所需的最低状态是什么。