Error when I'm trying to dispatch an action outside of my React Component, the state isn't updating
See original GitHub issueHi, I’m trying to dispatch an action from outside React’s logic.
This app is running with Electron.
Context of the problem: In this app I’m receiving push notifications through a third-party-service (Pushy), so we need to dispatch an action which set the new state en our reducer , so we can handle the info of the notification in a React Component later.
The data is being received in the main electron file (main.ts)
// Imports of my main.ts
import { app, BrowserWindow, screen } from 'electron';
import installExtension, {
REACT_DEVELOPER_TOOLS,
} from 'electron-devtools-installer';
import Pushy from 'pushy-electron';
import { setData } from './redux/reducers/setDataReducer';
import {store} from './redux/store';
This is how i define my dispatch method:
const dispatch = store.dispatch
This is the structure of the data that I’m trying to save in the store:
export interface DataReceived {
id: string;
message: [];
}
This is the portion of code where I’m trying to dispatch my action:
** Pushy.setNotificationListener() is a Listener function**
Inside the scope of this function I’m trying to dispatch my action setData(), declared in my reducer.
Pushy.setNotificationListener((data: DataReceived) => {
const auxData = JSON.stringify(data);
dispatch(setData(data))
// Display an alert with the "message" payload value
Pushy.alert(mainWindow, 'Received notification: ' + auxData);
});
My reducer:
setDataReducer.ts
Once my action is dispatched from my main.ts file I can see that the payload has the data that i need to set in my new state of the reducer
import { createSlice } from '@reduxjs/toolkit';
interface DataReceived {
id: string;
message: [];
}
let initialState: DataReceived = {
id: null,
message: [],
};
export const dataSetter = createSlice({
name: 'data',
initialState,
reducers: {
setData(state, action) {
console.log("action.payload: ", action.payload)
// Result of console.log()
// *********************
// action.payload: {
// id: 'd1b42186-64dc-42ca-b88f-64e40c58a1ef',
// message: '[{"story":{"id":"f53505c7-ae3c-4390-875a-e65b434b28f5","name":"Soy una historia","title":"Soy un titulo","description":"Soy una descripción","image":"https://storage.googleapis.com/vixonic-dashbX|oard/center","createdAt":2131221313},"tags":[]}]'
//
return {
...state,
id: action.payload.id,
message: action.payload.message,
};
},
},
});
export const { setData } = dataSetter.actions;
export default dataSetter.reducer;
store.ts
import {configureStore} from "@reduxjs/toolkit";
import { useDispatch } from "react-redux";
import { dataSetter } from "./reducers/setDataReducer";
export const store = configureStore({
reducer: dataSetter.reducer
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export const useAppDispatch : () => AppDispatch = useDispatch
export const selectStory = (state: RootState) => state
As the documentation suggests, i declared my hooks in a separate file to avoid circular import
hooks.ts
import {useDispatch, useSelector } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
This is my React component, the const story, is my selector of the state, and I’m passing as an argument the function selectStory() imported from the store file, this function basically is selecting the current state of the Redux store.
I’m trying to render the selected state in a p html tag, and only returns me the initial state of the reducer, and not the new one which is the one that I’m receiving in the payload
import React from 'react';
import { Grid } from '@mui/material';
import StoriesCarousel from '@src/components/Stories/StoriesCarousel';
import { useAppSelector, useAppDispatch } from '../redux/hooks'
import { selectStory } from '@src/redux/store';
export interface IStoriesProps {}
const Stories: React.FunctionComponent<IStoriesProps> = (props) => {
const story = useAppSelector(selectStory)
const stories: any[] = [
{
content: () => (
<div style={{ display: 'flex', flex: 1, justifyContent: 'center' }}>
<p>{JSON.stringify(story)}</p>
</div>
),
},
];
return (
<Grid container item display='flex' justifyContent='center'>
<StoriesCarousel stories={stories} />
</Grid>
);
};
export default Stories;
This is the graphic representation of my problem
I’ll be very glad if someone could help me, or telling me if the dispatch method is correctly used.
Regards
Issue Analytics
- State:
- Created a year ago
- Comments:6
Hi @markerikson, thanks for your support, i solved my problem, using the ipcMain and ipcRenderer functions for Electron, So then i could dispatch the action to the front end.
Main.ts (Electron file)
Renderer.tsx (Where my react app is rendered)
Unfortunately I’ve never used Electron myself, so I don’t have a good answer here.
I do know there’s tutorials and boilerplates out there that show how to add Redux to an Electron app - the only real suggestion that I can offer atm is to go read through some of those and see what’s different from your current setup.
Per immutable updates, yes, Immer lets you write “mutating” syntax like
state.nested.value = 123
instead of{...state, nested: {...state.nested, value: 123}}
. See these references: