Search code examples
reactjsreact-hookselectronreact-functional-componentipcrenderer

Electron/React cannot access component state changes in ipcRenderer listener


I am using Electron with React and I am facing a little problem.

I am creating a functional component and in the useEffect hook I subscribe to ipcRenderer to listen for when ipcMain replies.

When ipcRenderer event triggers I am unable to access the latest state updates. All state variables values inside ipcRenderer.on function contain data when the component was initially created.

In the code below customers is an array state variable. If I console.log its value every time the ipcRenderer.on is fired it is always empty. I am absolutely sure this variable is not empty inside the component's context because it contains information that is rendered in a grid. When ipcRenderer.on is triggered my grid is reset or cleared. All I am trying to do is refresh a row in the grid when ipcRenderer.on is triggered.

useEffect(() => {

    // Actions triggered in response to main process replies
    ipcRenderer.on(IPCConstants.UPDATE_SALE_CUSTOMER, (event: any, arg: IUpdateResponse) => {
    
        setIsLoading(false);

        if(!arg.success) {
            notifyError(arg.message);
            return;
        }

        setCustomers(
            customers.map(cst => {
                if(cst.CUS_CustomerId === arg.customer.CUS_CustomerId){
                    cst.RowId = `${generateRandomValue()}`;
                    cst.isActive = arg.customer.isActive;
                }
                return cst;
            })
        )
    });

    return () => {
        ipcRenderer.removeAllListeners(IPCConstants.UPDATE_SALE_CUSTOMER);
    };

}, []);

Solution

  • useEffect(() => {
    
        // Actions triggered in response to main process replies
        ipcRenderer.on(IPCConstants.UPDATE_SALE_CUSTOMER, (event: any, arg: IUpdateResponse) => {
        
            setIsLoading(false);
    
            if(!arg.success) {
                notifyError(arg.message);
                return;
            }
    
            setCustomers(
                customers.map(cst => {
                    if(cst.CUS_CustomerId === arg.customer.CUS_CustomerId){
                        cst.RowId = `${generateRandomValue()}`;
                        cst.isActive = arg.customer.isActive;
                    }
                    return cst;
                })
            )
        });
    
        return () => {
            ipcRenderer.removeAllListeners(IPCConstants.UPDATE_SALE_CUSTOMER);
        };
    
    }, [customers, otherState (if needed)]); // <= whichever state is not up to date 
    
    
    • You need to include the proper dependencies.
    • the useEffect will keep up to date with these state values
    • alternatively if you don't need the functionality of useState (unlikely) you can use useRef and the useEffect will always have the up to date ref without passing it as a dependency.