如何使用引用控制同级元素的行为?



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

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

我正在努力:

  1. 向每个InfoBox传递一个函数
  2. 当单击一个框时,将该事件发送到父元素(Modal(
  3. 然后在父元素中,循环遍历引用数组,找到单击图标的引用,并通过useImperativeHandle调用所有其他引用中的closeShowMore函数

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

提前感谢您抽出时间!

父级:

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}
>

就是这样。简而言之,你不想分散你的状态。总是问问自己,你需要描述的东西的最低状态是什么。

最新更新