React无状态组件中Office UI Fabric Panel的OnDismiss事件触发两次
onDismiss函数触发两次问题 嘿,我瞅了你的代码,发现几个可能导致这个问题的点,咱们一个个说:
最可能的原因:重复绑定/重复传递事件属性
首先看你CurrentProjects组件里渲染PopUpPanel的这段代码:
const popUpPanelProps:IPopUpPanelProps = { project: project, showPanel: this.state.showPanel, //onDismiss: this.onDismiss }; return ( <div className={styles.currentProjects}> {element} <PopUpPanel {...popUpPanelProps} onDismiss={this.onDismiss} /> </div> );
虽然你注释了popUpPanelProps里的onDismiss,但如果之前没注释的时候,相当于给PopUpPanel传了两次onDismiss属性——不过JSX里后面的属性会覆盖前面的,所以这个可能不是当前的核心问题,但还是建议统一传递方式,要么都放popUpPanelProps里,要么单独写,别混着来避免混淆。
更关键的是看你的PopUpPanel组件(虽然你只贴了开头):如果在这个组件里,你给Office UI Fabric的Panel组件重复绑定了onDismiss事件,比如同时绑定到自定义关闭按钮和面板自带的onDismiss属性上,那点击关闭图标时就会触发两次。比如错误的写法:
// 错误示例!别这么写 const PopUpPanel = (props) => { return ( <Panel isOpen={props.showPanel} onDismiss={props.onDismiss} > {/* 多余的自定义关闭按钮,又绑定了一次onDismiss */} <button onClick={props.onDismiss}>关闭</button> </Panel> ); };
这种情况下,点击Panel自带的关闭图标,会触发Panel的onDismiss,同时如果事件冒泡到内部按钮,就会导致函数执行两次。
另一个可能:React Strict Mode的锅
如果你是在开发环境遇到这个问题,那大概率是React Strict Mode搞的鬼。Strict Mode在开发环境下会刻意让某些函数(比如setState的更新函数、组件的render方法)执行两次,目的是帮你发现代码里的副作用问题。你的onDismiss里用了函数式setState:
private onDismiss():void{ this.setState((prevState:ICurrentProjectsState)=> { return { showPanel: false }; }); }
这个更新函数会被执行两次,但这只是开发环境的检查,生产环境不会有这个情况。你可以去项目入口文件里看看有没有<React.StrictMode>标签,去掉它试试,应该就不会触发两次了(不过不建议长期关闭,Strict Mode能帮你提前踩坑)。
解决方案
- 检查PopUpPanel的代码:确保你只给Office UI Fabric的
Panel组件绑定一次onDismiss={props.onDismiss},没有在其他地方(比如自定义关闭按钮、遮罩层)重复绑定这个函数。正确的写法应该是这样:
import * as React from 'react'; import { Panel, PanelType } from 'office-ui-fabric-react'; import IPopUpPanelProps from "./IPopUpPanelProps"; const PopUpPanel: React.FC<IPopUpPanelProps> = (props) => { return ( <Panel isOpen={props.showPanel} onDismiss={props.onDismiss} type={PanelType.smallFixedFar} // 其他必要属性 > {/* 你的面板内容 */} <h1>{props.project?.Title}</h1> </Panel> ); }; export default PopUpPanel;
- 统一属性传递方式:在
CurrentProjects里,把onDismiss统一放进popUpPanelProps里,避免混淆:
// 推荐写法:统一放进props对象里 const popUpPanelProps:IPopUpPanelProps = { project: project, showPanel: this.state.showPanel, onDismiss: this.onDismiss }; return ( <div className={styles.currentProjects}> {element} <PopUpPanel {...popUpPanelProps} /> </div> );
- 验证Strict Mode的影响:如果是开发环境的问题,去掉入口文件里的
<React.StrictMode>标签,看看是否解决问题。如果解决了,那就是Strict Mode的正常行为,不用慌,生产环境会正常。
总结
最可能的原因就是重复绑定了onDismiss事件,先检查你的PopUpPanel组件代码,确保只绑定一次。如果是开发环境的问题,那大概率是Strict Mode的原因,不用在意,生产环境会正常。
内容的提问来源于stack exchange,提问作者Shashank

