我正在将React Native应用程序转换为TypeScript,并且无法在商店外部调度重击动作。这是我目前的商店设置方式:
store / index.ts
import { createStore, applyMiddleware, combineReducers, Reducer, Store } from 'redux';
import thunk, { ThunkMiddleware } from 'redux-thunk';
export interface State { ... }
export interface ActionTypes { ... } // All of the non-thunk actions
const reducer: Reducer<State> = combineReducers({ ... });
export default (): Store<State> => {
return applyMiddleware(
thunk as ThunkMiddleware<State, ActionTypes>
)(createStore)(reducer);
}
index.tsx
import { Provider } from 'react-redux';
import createStore from './store/index';
import { registerStore } from './store/registry';
const store = createStore();
registerStore(); // Registers the store in store/registry.ts
AppRegistry.registerComponent(appName, () => () => (
<Provider store={store}>
<App />
</Provider>
));
商店/注册中心
import { Store } from 'redux';
import { State } from './index';
let store: Store<State>;
export const registerStore = (newStore: Store<State>) => {
store = newStore;
};
export const getStore = () => store;
因此,在创建商店后,我会将其存储在商店注册表中,以便可以从任何地方调用getStore()
。
这在组件(我不在使用注册表的地方)中很好用,例如在我的 App.tsx 中:
import { connect } from 'react-redux';
import { ThunkDispatch } from 'redux-thunk';
import { checkAuthStatus as checkAuthStatusAction } from './store/modules/auth/actions';
import { ActionTypes, State as AppState } from './store/index';
interface State = { ... }
interface StateProps { ... }
interface DispatchProps {
checkAuthStatus: () => Promise<boolean>;
}
type Props = StateProps & DispatchProps;
class App extends Component<Props, State> {
async componentDidMount() {
const promptSkipped: boolean = await checkAuthStatus(); // Thunk action, works fine!
}
...
}
const mapStateToProps = ...;
const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, null, ActionTypes>): DispatchProps => ({
checkAuthStatus: () => dispatch(checkAuthStatusAction()),
});
export default connect<StateProps, DispatchProps, {}, AppState>(
mapStateToProps,
mapDispatchToProps,
)(App);
当我想使用注册表分派重击操作时出现问题:
lib / notacomponent.ts
import { getStore } from '../store/registry';
import { checkAuthStatus, setLoggedIn } from '../store/modules/auth/actions'
const someFunction = () => {
const store = getStore();
const { auth } = store.getState(); // Accessing state works fine!
store.dispatch(setLoggedIn(true)); // NON-thunk action, works fine!
store.dispatch(checkAuthStatus()); // Uh-oh, thunk action doesn't work.
}
这给了我错误:
Argument of type 'ThunkAction<Promise<boolean>, State, null, Action<any>>' is
not assignable to parameter of type 'AnyAction'.
Property 'type' is missing in type 'ThunkAction<Promise<boolean>, State, null, Action<any>>'
but required in type 'AnyAction'. ts(2345)
据我所知,将thunk as ThunkMiddleware<State, ActionTypes>
用作中间件使Redux Thunk可以将store派发方法替换为一种可以派发thunk动作和常规动作的方法。 / p>
我认为我需要以某种方式键入注册表,以便TypeScript可以看到调度方法不是默认允许仅正常操作的默认方法。但是,我对如何执行此操作不知所措。我找不到任何其他人在做同样事情的例子。
感谢您的帮助。
编辑:建议的How to dispatch an Action or a ThunkAction (in TypeScript, with redux-thunk)? 重复项不能解决我的问题。我可以在组件内部调度重击动作。使用上面定义的商店注册表,我只会遇到组件外部的问题。
编辑2 :因此,当我分派重击操作来消除错误时,似乎可以使用以下类型断言:
(store.dispatch as ThunkDispatch<State, void, ActionTypes>)(checkAuthStatus())
但这是非常不切实际的。我还没有找到一种方法来使TypeScript知道dispatch
方法应该总是能够调度重击动作。
答案 0 :(得分:1)
您的代码几乎正确。您错误地设置了默认导出的返回类型。
export default (): Store<State> => {
return applyMiddleware(
thunk as ThunkMiddleware<State, ActionTypes>
)(createStore)(reducer);
}
在使用中间件的情况下,上面的函数应该不返回Store<State>
,而是返回Store<S & StateExt, A> & Ext
,其中Ext
将被重载dispatch
,将能够分派{{3} }(就像redux-thunk一样)。
为简化起见,只需删除确切的返回类型并让TypeScript推断类型本身
export default () => {
return applyMiddleware(
thunk as ThunkMiddleware<State, ActionTypes>
)(createStore)(reducer);
}
那可以解决您的问题。
或者,您可以使用更多经典方法来存储创建。
export default () => {
return createStore(reducer, applyMiddleware(thunk as ThunkMiddleware<State, ActionTypes>));
}
这里很重要:
按照functions的建议使用createStore
。以中间件作为第二个参数调用的createStore
本身Redux official doc。但是用于redux和redux-thunk的TypeScript声明文件已预先配置为使用createStore
。因此,退货的商店将有dispatch
的{{3}}。 (请注意Ext and StateExt
的{{1}}类型参数。它们将与结果存储区相交,并添加StoreEnhancer<Ext, StateExt>
的重载版本,该版本将接受函数作为参数。)
还可以从dispatch
的返回类型中推断出默认导出功能的返回类型。不会是createStore
。
答案 1 :(得分:1)
const boundActions = bindActionCreators( { checkAuthStatus }, store.dispatch);
boundActions.checkAuthStatus();
这有效并且看起来不像'Edit2'那样笨拙