Javascript 事件处理程序get';在设置处理程序之前调用
我的react应用程序中有这个可重用组件Javascript 事件处理程序get';在设置处理程序之前调用,javascript,reactjs,state,Javascript,Reactjs,State,我的react应用程序中有这个可重用组件 export const OutsideWrapper = ({ children, onOutside, className }) => { const wrapperRef = useRef(null); const [style, setStyles] = useState({ opacity: 1 }); useEffect(() => { console.log("1. component was m
export const OutsideWrapper = ({ children, onOutside, className }) => {
const wrapperRef = useRef(null);
const [style, setStyles] = useState({
opacity: 1
});
useEffect(() => {
console.log("1. component was mounted");
const i = e => {
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
console.log("3. outside click was trigerred");
e.preventDefault();
setStyles({ opacity: 0 });
setTimeout(() => {
onOutside();
}, 100);
}
};
window.addEventListener("click", i, true);
console.log('2. listener was added');
return () => {
console.log("4. listerner was removed");
window.removeEventListener("click", i, true);
};
}, [onOutside]);
return (
<div
ref={wrapperRef}
style={style}
className={`outside-wrapper ${className}`}
>
{children}
</div>
);
};
当React渲染组件时,会调用
窗口.addEventListener
调用useEffect
,这发生在焦点上。引起焦点的事件不是点击,而是一个mousedown
。当下一个mouseup
发生时,也会生成一个被捕获的点击事件。请注意,如果您在输入中按tab键以聚焦,则不会导致错误
有几种方法可以解决这个问题,但我的建议是忽略在输入本身上发生的单击事件
这里有一个例子:我向
添加了一个ref,将其传递到外部包装器中,并为新的ref添加了一个类似于您为包装器ref
所做的检查
function Test() {
const [down, setDown] = React.useState(false);
const focusRef = React.useRef();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>
<input ref={focusRef} onFocus={() => setDown(true)} />
{down && (
<OutsideWrapper
onOutside={() => setDown(false)}
focusedRef={focusRef}
className="input-wrapper"
>
children
</OutsideWrapper>
)}
</h2>
</div>
);
}
const OutsideWrapper = ({ children, onOutside, className, focusedRef }) => {
const wrapperRef = React.useRef(null);
const [style, setStyles] = React.useState({
opacity: 1
});
React.useEffect(() => {
console.log("1. component was mounted");
const i = e => {
console.log(e.target, wrapperRef.current);
if (
wrapperRef.current &&
!wrapperRef.current.contains(e.target) &&
focusedRef.current !== e.target
) {
console.log("3. outside click was trigerred");
e.preventDefault();
setStyles({ opacity: 0 });
setTimeout(() => {
onOutside();
}, 100);
}
};
window.addEventListener("click", i, true);
console.log("2. listener was added");
return () => {
console.log("4. listerner was removed");
window.removeEventListener("click", i, true);
};
}, [onOutside, focusedRef]);
return (
<div
ref={wrapperRef}
style={style}
className={`outside-wrapper ${className}`}
>
{children}
</div>
);
};
功能测试(){
const[down,setDown]=React.useState(false);
const focusRef=React.useRef();
返回(
你好,代码沙盒
设置(正确)}/>
{向下&&(
设置(错误)}
focusedRef={focusRef}
className=“输入包装器”
>
儿童
)}
);
}
const OutsideWrapper=({子项,外部,类名,focusedRef})=>{
const wrapperRef=React.useRef(null);
const[style,setStyles]=React.useState({
不透明度:1
});
React.useffect(()=>{
控制台日志(“1.组件已安装”);
常数i=e=>{
日志(如target、wrapperRef.current);
如果(
包装器参考电流&&
!wrapperRef.current.contains(例如目标)&&
focusedRef.current!==e.target
) {
console.log(“3.触发外部点击”);
e、 预防默认值();
setStyles({opacity:0});
设置超时(()=>{
onOutside();
}, 100);
}
};
window.addEventListener(“单击”,i,true);
console.log(“添加了2.listener”);
return()=>{
console.log(“4.listerner被删除”);
window.removeEventListener(“单击”,i,true);
};
},[onOutside,focusedRef]);
返回(
{儿童}
);
};
function Test() {
const [down, setDown] = React.useState(false);
const focusRef = React.useRef();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>
<input ref={focusRef} onFocus={() => setDown(true)} />
{down && (
<OutsideWrapper
onOutside={() => setDown(false)}
focusedRef={focusRef}
className="input-wrapper"
>
children
</OutsideWrapper>
)}
</h2>
</div>
);
}
const OutsideWrapper = ({ children, onOutside, className, focusedRef }) => {
const wrapperRef = React.useRef(null);
const [style, setStyles] = React.useState({
opacity: 1
});
React.useEffect(() => {
console.log("1. component was mounted");
const i = e => {
console.log(e.target, wrapperRef.current);
if (
wrapperRef.current &&
!wrapperRef.current.contains(e.target) &&
focusedRef.current !== e.target
) {
console.log("3. outside click was trigerred");
e.preventDefault();
setStyles({ opacity: 0 });
setTimeout(() => {
onOutside();
}, 100);
}
};
window.addEventListener("click", i, true);
console.log("2. listener was added");
return () => {
console.log("4. listerner was removed");
window.removeEventListener("click", i, true);
};
}, [onOutside, focusedRef]);
return (
<div
ref={wrapperRef}
style={style}
className={`outside-wrapper ${className}`}
>
{children}
</div>
);
};