React-Electron应用中State更新后IPC回调未同步问题求助
问题分析与解决方案
问题根源
- 闭包陷阱:
Test1函数在组件首次渲染时创建,捕获了初始状态下的空数组sources。后续点击「Get Sources」更新sources后,IPC监听器绑定的仍是旧版本的Test1,因此触发时输出的还是旧的空数组状态。 - 过度清理监听器:两个
useEffect的清理函数都调用ipcRenderer.removeAllListeners(),这会移除所有IPC监听器(包括GET_SOURCES通道的监听器),可能导致后续操作失效。
修复步骤
1. 精准清理IPC监听器
不要使用removeAllListeners(),改为移除对应通道的特定监听器,避免误删其他通道的监听逻辑。
2. 让Test1追踪sources状态变化
使用useCallback包裹Test1,将sources设为依赖项,确保每次sources更新时生成新的函数实例;同时在绑定IPC监听器的useEffect中加入Test1作为依赖,实现监听器的动态更新。
修改后的代码
Recorder.jsx
import { useEffect, useState, useCallback } from 'react' import { channels } from '../../../../shared' import { Button } from 'primereact/button' const { ipcRenderer } = electron function Recorder() { const [sources, setSources] = useState([]) const handleSources = (_, sources) => { setSources(sources) } const getScreenSources = () => { ipcRenderer.send(channels.GET_SOURCES) } useEffect(() => { ipcRenderer.on(channels.GET_SOURCES, handleSources) // 精准移除当前通道的监听器 return () => { ipcRenderer.removeListener(channels.GET_SOURCES, handleSources) } }, []) const Test = () => { ipcRenderer.send(channels.TEST) } // 使用useCallback包裹,依赖sources确保函数更新 const Test1 = useCallback(() => { console.log('Test ', sources) }, [sources]) useEffect(() => { ipcRenderer.on(channels.TEST, Test1) // 精准移除当前通道的监听器 return () => { ipcRenderer.removeListener(channels.TEST, Test1) } }, [Test1]) // 依赖Test1,函数更新时重新绑定监听器 return ( <div> <Button label="Test" onClick={Test} /> <Button label="Get Sources" onClick={getScreenSources} /> {sources.map((source) => ( <li key={source.id}>{source.name}</li> ))} </div> ) } export default Recorder
额外优化
渲染列表时增加key属性(使用source.id),符合React列表渲染的最佳实践,避免不必要的重渲染。
内容的提问来源于stack exchange,提问作者Musaib
相关产品推荐
相关产品推荐

