【发布时间】:2018-06-05 14:23:17
【问题描述】:
当动作被分派到映射到该组件的减速器时,我在更新我的 react 组件上的 props 属性时遇到问题。我将在显示代码的过程中进行解释。
首先,我试图在我的 react 组件之外调度操作(从 Electron 菜单项单击触发的调度)。
这是调度操作的菜单服务函数。如果我们在派发后执行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 文件,我在其中引导 App 组件并使用相同的商店提供程序加载商店(这将填充 StoreProvider 的新实例,构造函数将在其中设置我稍后可以访问的商店菜单项点击):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import allReducers from './reducers/index';
import App from './app';
import StoreProvider from './providers/store-provider';
const bootstrapperElement: HTMLElement = document.getElementById('app') as HTMLElement;
const store = StoreProvider.getInstance().store;
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
bootstrapperElement);
好的,这就是将事情连接到发送动作的点的方式。所以当我在菜单服务函数中调度我的动作时,它正在调用这个动作:
export const loadMessage = (message: any) => {
return {
type: 'MESSAGE_LOADED',
payload: message
};
};
一旦 action 被调度,它就会被这个 reducer 拾取。请注意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);
因此,当我单击带有文本“TEST”的 h2 元素时,我总是得到 null,这是最初传递给接收该消息的减速器的默认值(尽管上面我们知道控制台。当从菜单服务分派操作时,登录减速器确实打印了正确的值。
这也是我要添加到商店的减速器:
import { combineReducers } from 'redux';
import FileExplorerReducer from './file-explorer';
const allReducers = combineReducers({
fileExplorer: FileExplorerReducer
});
export default allReducers;
在此问题上的任何帮助将不胜感激。我相信此时我倾向于它是 StoreProvider 的一个问题,并且可能有 2 个单独的商店实例?不太清楚为什么组件 this.props.fileExplorer 始终为 null,即使 reducer 返回 action.payload 并且 store 的 fileExplorer 状态已更新(至少在调度后检查菜单服务)。
根据接受的答案更改上述问题的答案:
因此必须允许 IPC(进程间通信),我们必须像这样在菜单服务中从 BrowserWindow.webContents.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());
}
}
【问题讨论】:
-
尝试控制台在您的 Sidemenu 组件 mapstatetoprops 中记录您的状态,以确保您拥有正确的状态
-
@cdoshi 就是这么做的,哈哈。它给了我一个属性为“fileExplorer:null”的对象。肯定认为商店发生了一些有趣的事情
-
还只是在使用随机数创建商店时为 fileExplorer 添加了一个默认值,在 Provider 中加载商店时的实例上,我得到了 52,然后当我得到了store in the menu service 我得到了 75。所以确认有两个单独的 store 实例,只需要弄清楚如何将它保持在一个。以为我正在实现一个单例来使用。
-
从您上面的代码来看,您似乎没有多个商店。很抱歉在这里没有太大帮助
-
各位好人,感谢您抽出宝贵时间观看!
标签: javascript reactjs typescript redux react-redux