javascript - 如何使用 refs 控制兄弟元素的行为?
问题描述
我有Modal
带有信息框的组件。在每个InfoBox
按钮(图标)中都显示了有关产品特定成分的更多信息。该功能包含在每个InfoBox
组件中。
当您单击一个 InfoBox 中的按钮(图标)时,我希望所有其他 InfoBox(es) 关闭 - 如何使用 refs 控制兄弟元素的行为?
我试图:
- 将函数向下传递给每个 InfoBox
- 单击一个框时,将该事件发送到父元素(模态)
- 然后在父元素中,遍历引用数组,找到单击图标的那个,并在所有其他引用中
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;
孩子:
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
name="ibu"
{your other props}
expandInfoBox={() => setExpandedInfoBoxName("ibu")
showMore={expandedInfoBoxName === "ibu"}
/>
在您的 InfoBox 中,您删除您的状态和函数 useImperativeHandle、openShowMore 和 closeShowMore。添加这个来获得你的新道具:
const { name, value, imageUrl, expandInfoBox, showMore } = props;
然后在你的 jsx 中你做:
<div
className="plus-minus-icon-wrapper"
onClick={expandInfoBox}
>
就是这样。简而言之,你不想分散你的状态。总是问自己,描述某事所需的最低限度是什么。
推荐阅读
- object - CEPH 对象如何存储文件
- powerbi - Power BI - 评估逻辑并突出显示小计(条件格式)
- javascript - 我得到了一个指数:10;从 vscode 的终端
- bash - 如何遵循哪个输出的符号链接?
- java - 在 Spark 的驱动程序上捕获 Dataset foreachPartition() 函数中引发的异常?
- c# - 如何等待元素附加到 DOM
- c# - 如何在 OpenXML SpeadsheetDocument 中设置或清除作者
- wordpress - 将 Bootstrap 4 网站迁移到 Wordpress
- javascript - React.js:父级或组件应该管理状态吗?
- php - 删除 var_dump 时 dateTime 出错