Javascript Redux reducer未从React组件外部调度更新React组件中的prop值
当一个动作被分派到映射到该组件的减速器时,我在更新react组件上的props属性时遇到问题。我将在显示代码的过程中进行解释 因此,首先,我尝试在我的react组件之外分派操作(从Electron菜单项单击激发分派) 这是分派操作的菜单服务功能。如果在分派后执行Javascript Redux reducer未从React组件外部调度更新React组件中的prop值,javascript,reactjs,typescript,redux,react-redux,Javascript,Reactjs,Typescript,Redux,React Redux,当一个动作被分派到映射到该组件的减速器时,我在更新react组件上的props属性时遇到问题。我将在显示代码的过程中进行解释 因此,首先,我尝试在我的react组件之外分派操作(从Electron菜单项单击激发分派) 这是分派操作的菜单服务功能。如果在分派后执行console.log(store.getState()),我们将正确地看到处于存储状态的消息: dispatchMessage(): void { let message = messageService.getMessage(
console.log(store.getState())
,我们将正确地看到处于存储状态的消息:
dispatchMessage(): void {
let message = messageService.getMessage();
let store = StoreProvider.getInstance().store;
store.dispatch(loadMessage(message));
}
请注意,StoreProvider获得了Redux存储的实例,之所以这样做是因为代码不在React组件的范围内,这是StoreProvider.ts:
import { createStore } from 'redux';
import allReducers from '../reducers/index';
export default class StoreProvider {
private static _instance: StoreProvider;
store: any = null;
constructor() {
this.store = createStore(
allReducers
);
}
public static getInstance(): StoreProvider {
return StoreProvider._instance || (StoreProvider._instance = new StoreProvider());
}
}
这是我的index.tsx文件,我在其中引导应用程序组件并使用相同的存储提供程序加载存储(这将填充存储提供程序的新实例,构造函数将在其中设置我稍后可以在菜单项单击中访问的存储):
一旦动作被分派,它就会被这个减速机拾取。请注意console.log(action.payload)
,此时它将正确记录从菜单服务发送的消息,并且我可以看到预期的内容,到目前为止似乎正在工作
export default (state: any = null, action: any) => {
switch (action.type) {
case 'MESSAGE_LOADED':
console.log(action.payload);
return action.payload;
default:
return state;
}
};
这是将该状态映射到道具的组件:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
class SideMenu extends Component<any> {
render() {
return (
<div>
<h2 onClick={ () => console.log(this.props.fileExplorer)}>Test</h2>
</div>
);
}
}
const mapStateToProps = (state: any) => {
return {
fileExplorer: state.fileExplorer
};
};
export default connect<any>(mapStateToProps, {})(SideMenu);
在此问题上的任何协助都将不胜感激。我相信在这一刻,我倾向于这是一个与商店供应商的问题,可能有2个商店的独立实例?不太清楚为什么组件this.props.fileExplorer总是空的,即使reducer返回action.payload并且存储的fileExplorer状态已更新(至少在分派后通过检查菜单服务)
根据接受的答案更改以上问题的答案:
因此,为了允许IPC(进程间通信),我们必须在菜单服务中发布来自BrowserWindow.WebContent.send()的消息,如下所示:
let message = let message = messageService.getMessage();
BrowserWindow.getFocusedWindow().webContents.send('dispatch-action', { payload: { message});
然后在Store Provider中,我在构造函数中添加了订阅者,以便Store的实例可以接收从渲染器进程中的主进程发布的消息,如下所示:
import { ipcRenderer } from 'electron';
export default class StoreProvider {
private static _instance: StoreProvider;
store: any = null;
constructor() {
this.store = createStore(
allReducers
);
ipcRenderer.on('dispatch-action', (event: any, arg: any) => {
this.store.dispatch(loadMessage(arg.payload));
});
}
public static getInstance(): StoreProvider {
return StoreProvider._instance || (StoreProvider._instance = new StoreProvider());
}
}
我不能完全确定,但根据您的描述,您正在尝试执行Electron的菜单事件,我建议您检查发送菜单事件的进程。如果不是承载react组件的渲染器进程,您可能会看到每个不同的进程都有独立的存储状态,可能需要用于redux的存储同步中间件,或者在渲染器进程中调用IPC,然后让渲染器直接为渲染器端redux存储分派操作。在非react组件中调用
store.dispatch()
时,我也会遇到同样的问题。我不确定这是否是正确的方法,但我可以通过将存储传递到组件并从组件中修复它,将接收到的存储传递给非react组件,然后使用这个接收到的存储来分派我的操作
index.js
<Provider store={configstore}>
<BrowserRouter>
<App>
<Switch>
<Route exact path="/addinvoice" component={authGuard(AddInvoice)} storeHack={configStore} />
</Switch>
</App>
</BrowserRouter>
</Provider>
参考:
}尝试将您的状态记录到侧菜单组件MapStateTops中,以确保您拥有正确的state@cdoshi刚刚做了那个lol。它给了我一个属性为“fileExplorer:null”的对象。当然,我觉得这个商店有点搞笑。当这个商店是由一个随机数创建的时候,我刚刚为fileExplorer添加了一个默认值。在这个实例上,当这个商店加载到提供者中时,我得到了52个,当我在菜单服务中得到了这个商店的一个实例时,我得到了75个。因此,它被确认有两个不同的商店实例,只需找出如何保持在一个。我以为我在实现一个要使用的单例。从上面的代码来看,似乎没有多个存储。对不起,我帮不上什么忙。所有的好人,感谢你抽出时间来看我!
let message = let message = messageService.getMessage();
BrowserWindow.getFocusedWindow().webContents.send('dispatch-action', { payload: { message});
import { ipcRenderer } from 'electron';
export default class StoreProvider {
private static _instance: StoreProvider;
store: any = null;
constructor() {
this.store = createStore(
allReducers
);
ipcRenderer.on('dispatch-action', (event: any, arg: any) => {
this.store.dispatch(loadMessage(arg.payload));
});
}
public static getInstance(): StoreProvider {
return StoreProvider._instance || (StoreProvider._instance = new StoreProvider());
}
}
<Provider store={configstore}>
<BrowserRouter>
<App>
<Switch>
<Route exact path="/addinvoice" component={authGuard(AddInvoice)} storeHack={configStore} />
</Switch>
</App>
</BrowserRouter>
</Provider>
class AddInvoice extends Component {
constructor(props){
super(props)
this.state={
store:props
}
console.log("store received in add invoice is",this.state)
}
render(){
return(
//pass this.state.store to the non react-component
//and use the received parameter.dispatch(actionName) in ur non-react component and u ready to go
)