Javascript 为什么一个函数通过道具传递到一个子组件中,在按键和点击按钮时表现不同?
我有一个React项目,其中父组件(功能)保持状态,以确定应用于列表的格式。当用户单击按钮时,会生成一个模式-我将匿名函数作为道具传递给该模式(Javascript 为什么一个函数通过道具传递到一个子组件中,在按键和点击按钮时表现不同?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我有一个React项目,其中父组件(功能)保持状态,以确定应用于列表的格式。当用户单击按钮时,会生成一个模式-我将匿名函数作为道具传递给该模式(onMainButtonClick),调用该函数时会翻转状态并更改列表的格式(此逻辑在父组件中) 当我在模态组件中使用按钮(onClick={()=>onMainButtonClick()})时,代码按预期工作。但是,我也希望按下enter键来触发此操作。因此,我为此实现了以下代码,但它没有按预期工作。模式关闭,函数启动(我知道这是因为我在那里放了一个控
onMainButtonClick
),调用该函数时会翻转状态并更改列表的格式(此逻辑在父组件中)
当我在模态组件中使用按钮(onClick={()=>onMainButtonClick()}
)时,代码按预期工作。但是,我也希望按下enter键来触发此操作。因此,我为此实现了以下代码,但它没有按预期工作。模式关闭,函数启动(我知道这是因为我在那里放了一个控制台日志…),但是影响格式的状态没有改变
编辑:在下面做了一个建议的更改(对onEnterPress函数进行备注,以便正确删除它),下面是模式的完整代码:
import { React, useRef, useEffect, useCallback } from "react";
import ReactDOM from "react-dom";
const Modal = ({
title,
description,
isOpen,
onClose,
onMainButtonClick,
mainButtonText,
secondaryButtonText,
closeOnly,
}) => {
const node = useRef();
const onEnterPress = useCallback(
(e) => {
if (e.key === "Enter") {
onMainButtonClick();
}
},
[onMainButtonClick]
);
useEffect(() => {
window.addEventListener("keydown", onEnterPress);
return () => {
window.removeEventListener("keydown", onEnterPress);
};
}, [onMainButtonClick]);
const handleClickOutside = (e) => {
if (node.current.contains(e.target)) {
return null;
}
onClose();
};
if (!isOpen) return null;
return ReactDOM.createPortal(
{// JSX here, removed for brevity},
document.body
);
};
export default Modal;
以及父项的代码(显示模式并向下传递到MainButtonClick):
从“React”导入{React,useState};
从“html实体”导入{decode};
从“../../queries/useList”导入useList;
从“../../translations/useBuyItem”导入useBuyItem;
从“./共享/标题”导入标题;
从“./Shared/Description”导入说明;
从“/ListItem”导入ListItem;
从“/BuyOverlay”导入BuyOverlay;
从“./Modal”导入模态;
从“/ViewOperations”导入ViewOperations;
常量视图=(道具)=>{
const[buyOverlayOpen,setBuyOverlayOpen]=useState(false);
const[ViewBuyerOverlayopen,SetBuyerOverlayopen]=useState(false);
const[viewBullers,setviewBullers]=useState(false);
const[buyItemId,setBuyItemId]=useState();
const{isLoading,isError,data,error}=useList(props.match.params.id);
const buyItemMutation=useBuyItem(buyItemId,props.match.params.id,()=>
setBuyOverlayOpen(假)
);
如果(孤岛加载){
返回加载列表。。。;
}
如果(isError){
返回发生错误,请刷新后重试;
}
返回(
SetViewBullers(!ViewBullers)}
ToggleBuyerOverlay={()=>
SetBuyerOverlayopen(!ViewBuyerOverlayopen)
}
viewbullers={viewbullers}
/>
{data.items.length==0
?“此列表中未添加任何项目”
: ""}
{data.items.map((item)=>{
返回(
{
setBuyItemId(项目编号);
setBuyOverlayOpen(真);
}}
key={item.\u id}
viewbullers={viewbullers}
/>
);
})}
setBuyOverlayOpen(假)}
OnConfigrmClick={(buyerName)=>{
突变(buyerName);
}}
/>
{
SetBuyerOverlayopen(假);
}}
onMainButtonClick={()=>{
SetViewBudders(真);
SetBuyerOverlayopen(假);
}}
mainButtonText=“确定”
secondaryButtonText=“取消”
/>
);
};
导出默认视图;
你知道为什么会这样吗?我觉得这可能与这里的useEffect有关,但我有点不知所措……
onenterprisess
很可能直接定义在功能组件中,这就是为什么每次组件重新渲染时它的引用都会更改。您的useffect
会在每次渲染时关闭此新定义的函数,因此处理程序将无法按预期工作。
您可以使用useCallback
包装您的onEnterPress
,以记忆处理程序onEnterPress
,使其定义在整个渲染过程中保持不变,如下所示:
const onEnterPress = useCallback(e => {
if (e.key === "Enter") {
onMainButtonClick();
}
}, [onMainButtonClick]); // Another function dep. You can also wrap it with useCallback or carry over its logic into the callback here
useEffect(() => {
window.addEventListener('keydown', onEnterPress);
return () => {
window.removeEventListener('keydown', onEnterPress);
};
}, [onEnterPress]);
我最终发现了这一点-结果很简单,因为我的enterPress回调需要在if块之前使用preventDefault语句(
e.preventDefault()
)
页面上一定有其他东西捕获了enter键并导致其行为异常。首先,您对效果有一个未声明的依赖项,即
onMainButtonClick
,这可能是问题的一部分,但这取决于您未提供的周围代码。你能扩展这个问题并提供更多的细节吗?那么你想在页面上听回车吗?是的,当模态打开时,我想在页面上听回车@PierPaoloRamon我将尝试在上面给出更多的细节,这是有意义的,而且听起来是一个很好的调整,因为正如您所描述的,onenterprisess是在功能组件内部定义的。然而,我已经做出了改变,仍然遇到同样的问题。将尝试在上面发布更多细节。
const onEnterPress = useCallback(e => {
if (e.key === "Enter") {
onMainButtonClick();
}
}, [onMainButtonClick]); // Another function dep. You can also wrap it with useCallback or carry over its logic into the callback here
useEffect(() => {
window.addEventListener('keydown', onEnterPress);
return () => {
window.removeEventListener('keydown', onEnterPress);
};
}, [onEnterPress]);