首先,抱歉我的标题不好。
我的目标是使用此自定义挂钩检测组件外部的点击:
const useOutsideClick = (callback) => {
const reference = useRef();
useEffect(() => {
const handleClick = (event) => {
if (reference.current && !reference.current.contains(event.target)) {
console.log(reference.current);
console.log(event.target);
callback();
}
};
document.addEventListener("click", handleClick);
return () => {
document.removeEventListener("click", handleClick);
};
}, [reference]);
return reference;
};
我有一个
<HeaderSearch />
自定义组件,如下所示:
const HeaderSearch = ({ screenWidth }) => {
function checkInput(event) {
if (event.keyCode !== 13) {
setSearch(event.target.value);
}
}
const mobileRef = useOutsideClick(test);
const ref = useOutsideClick(test);
if (location.pathname !== "/") {
if (screenWidth == "mobile") {
return (
<div id="search-header" className="search-header mob" ref={mobileRef}>
<FontAwesomeIcon
className="search-icon"
id="search-icon"
icon={faSearch}
onClick={() => toggleSearchInput()}
/>
<input
id="search-input"
className={searchActive ? "search-input active" : "search-input"}
type="text"
value={search}
onKeyDown={(e) => checkInput(e)}
onChange={(e) => setSearch(e.target.value)}
// ref={searchInputRef}
// onClick={() => searchReqClientSide()}
placeholder="Search..."
/>
<button></button>
</div>
);
} else {
return (
<div id="search-header" className="search-header desk" ref={ref}>
<FontAwesomeIcon
className="search-icon"
id="search-icon"
icon={faSearch}
onClick={() => toggleSearchInput()}
/>
<input
id="search-input"
className={searchActive ? "search-input active" : "search-input"}
type="text"
value={search}
onKeyDown={(e) => checkInput(e)}
onChange={(e) => setSearch(e.target.value)}
// ref={searchInputRef}
// onClick={() => searchReqClientSide()}
placeholder="Search..."
/>
<button></button>
</div>
);
}
} else {
return null;
}
};
由于 css 类,HeaderSearch 组件是有条件渲染的。如果父标题元素具有活动类:将没有活动的标题的显示更改为不显示。
但是,当我单击组件外部时。两个 HeaderSearch 组件仍在调用自定义挂钩。请参阅下面的屏幕截图:
如何才能使只有处于活动状态的
<HeaderSearch/>
才调用 useOutsideClick 挂钩,而不是每次点击都触发?
编辑:我忘记添加 Test 回调(它是一个简单的日志):
function test() {
console.log("clicked outside");
}
重构逻辑,只需要一个
useOutsideClick
钩子。由于标题内容(即子项)对于移动设备和桌面视图来说似乎是相同的,因此您可以创建一个包装器组件来替换包装 div
元素,有条件地应用正确的 CSS className
prop、 和任何其他布局/移动和桌面视图之间的 UI 差异。
实施示例:
const SearchHeaderWrapper = ({
children,
onClickOutside,
screenWidth
}) => {
const ref = useOutsideClick(onClickOutside);
return (
<div
ref={ref}
id="search-header"
className={[
"search-header",
screenWidth == "mobile" ? "mob" : "desk"
].join(" ")}
ref={ref}
>
{children}
</div>
);
};
const HeaderSearch = ({ screenWidth }) => {
const ref = useOutsideClick(test);
...
function checkInput(event) {
if (event.keyCode !== 13) {
setSearch(event.target.value);
}
}
if (location.pathname !== "/") {
return (
<SearchHeaderWrapper
onClickOutside={test}
screenWidth={screenWidth}
>
<FontAwesomeIcon
className="search-icon"
id="search-icon"
icon={faSearch}
onClick={() => toggleSearchInput()}
/>
<input
id="search-input"
className={["search-input", searchActive && "active"]
.filter(Boolean)
.join(" ")
}
type="text"
value={search}
onKeyDown={(e) => checkInput(e)}
onChange={(e) => setSearch(e.target.value)}
// ref={searchInputRef}
// onClick={() => searchReqClientSide()}
placeholder="Search..."
/>
<button></button>
</div>
);
} else {
return null;
}
};