我正在使用React,Redux,Redux-Thunk和Typescript(noobie)。当我使用重击调用动作时,可以看到该动作被调用(使用console.log),而调度未被调用。我已经使用mapToDispatch连接了此动作,并使用this.props。(action)从组件中调用了它。我不知道为什么不调用调度。这是我的代码:
store.ts
import { applyMiddleware, combineReducers, createStore, Store, compose } from 'redux'
import { ReducerMap, StoreShape, SYSTEM_STATE_NAMESPACE_KEY } from './types'
import thunkMiddleware from 'redux-thunk'
import systemReducer from './globalData/reducer'
import { Environment, getCurrentEnvironment } from '../services/api.service'
let reducerMap: ReducerMap = { [SYSTEM_STATE_NAMESPACE_KEY]: systemReducer }
const isDevelopmentEnvironment = [Environment.LOCALHOST, Environment.STAGING].includes(getCurrentEnvironment())
export default function configureStore() {
const middleware = [thunkMiddleware]
const middlewareEnhancer = applyMiddleware(...middleware)
let composedEnhancers = isDevelopmentEnvironment
? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
: compose
const preloadedState = (window as any).__PRELOADED_STATE__;
delete (window as any).__PRELOADED_STATE__;
return createStore(combineReducers(reducerMap), preloadedState, composedEnhancers(middlewareEnhancer))
}
export const store = configureStore()
export function getStore() {
return store
}
actions.js
import { SearchActionTypes, SearchNamespaceShape } from './types'
import axios from '../../../services/axiosInstance'
import { Action } from 'redux'
import { StoreShape } from '../../../store/types'
import { getAPIDomain } from '../../../services/api.service'
export function getSearchResults (): ThunkAction<void, StoreShape, void, Action> {
console.log('inside function')
return (dispatch) => {
console.log('inside dispatch')
const body: object = {
"query": {
"bool": {
"must": [
{
"match": {
"title": "CEO"
}
}
]
}
}
}
axios.post(
'https://' + getAPIDomain() + '/proxy-service/ROOT/search/_search',
body
)
.then((response: object):any => console.log(response))
.catch((response: object):any => console.log(response))
}
}
容器
import { connect, Provider } from 'react-redux'
import * as React from 'react'
import { getStoreForSearch } from './data/store'
import { getGlobalData } from '../../store/globalData/selectors'
import UnconnectedSearchPage, { StateProps, DispatchProps, OwnProps } from './search'
import { StoreShape } from '../../store/types'
import { getSearchResults } from './data/actions'
const SearchContainer: React.FC = () => {
return (
<Provider store={getStoreForSearch({})} >
<ConnectedSearchPage textToDisplay='Hello World'/>
</Provider>)
}
function mapStateToProps (state: StoreShape, ownProps: OwnProps): StateProps {
return(
{
system: getGlobalData(state)
}
)
}
const mapDispatchToProps = (dispatch: any, ownProps: OwnProps): DispatchProps => ({
getSearchResults: () => dispatch(getSearchResults)
})
const ConnectedSearchPage = connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
UnconnectedSearchPage
)
export default SearchContainer
component
import React from 'react'
import { ThunkAction } from 'redux-thunk'
import { Action } from 'redux'
import { GlobalDataNamespaceShape } from '../../store/globalData/types'
import { FullStoreShape } from '../../store/types'
export interface OwnProps {
textToDisplay: string
labelText?: string
}
export interface StateProps {
system: GlobalDataNamespaceShape
}
export interface DispatchProps {
getSearchResults: () => ThunkAction<void, Partial<FullStoreShape>, undefined, Action<object>>
}
export type SearchComponentProps = StateProps & DispatchProps & OwnProps
interface SearchState {
greeting: string
}
export default class UnconnectedSearchPage extends React.Component<SearchComponentProps, SearchState> {
constructor(props: SearchComponentProps) {
super(props)
this.state = { greeting: props.textToDisplay }
}
setGreeting( greeting: string): void {
this.setState({ greeting })
}
render () {
console.log(this.props)
return (
<div>
<h2>Search Page</h2>
<div>{`Greeting: ${this.state.greeting}`}</div>
<label>{this.props.labelText}</label>
<input
type='text'
value={this.state.greeting}
onChange={event => this.setGreeting(event.target.value)}
/>
<button onClick={() => {
this.props.getSearchResults()
}}>Get Search Results</button>
</div>
)
}
}
似乎您正在分派thunk动作,但是您实际上并没有在thunk动作中分派动作。
[当分派一个动作getSearchResults
时,将返回一个将dispatch
方法作为参数的函数,您已经在return (dispatch) => {
中正确指出了该函数。您可以使用该调度方法来调度进一步的操作。
您必须调用该调度方法才能生效。可能需要在promise回调中执行此操作,以处理从API调用返回的数据,然后将其存储在redux中。有点像...
export function getSearchResults (): ThunkAction<void, StoreShape, void, Action> {
return (dispatch) => {
const body: object = {
...
}
axios.post(
'https://' + getAPIDomain() + '/proxy-service/ROOT/search/_search',
body
)
.then((response: object): void => {
const data = extractData(response)
dispatch({
type: UPDATE_SEARCH_RESULTS,
payload: data,
})
})
.catch((response: object):any => console.log(response))
}
}
然后您应该在减速器中收到该UPDATE_SEARCH_RESULTS
操作。
[如果您打算对API调用大量使用redux操作,强烈建议使用像https://www.npmjs.com/package/redux-api-middleware这样的中间件来为您保持干净。
我发现映射这样的调度可以解决我的问题-但我不是100%知道为什么...:
const mapDispatchToProps = (dispatch: any, ownProps: OwnProps): DispatchProps => {
return {
getSearchResults: () => dispatch(getSearchResults()),
}
}