【问题标题】:Thunk Action not being called by dispatch - using Typescript调度未调用 Thunk Action - 使用 Typescript
【发布时间】:2020-03-17 20:34:19
【问题描述】:

我正在使用 React、Redux、Redux-Thunk 和 Typescript(noobie)。 当我用 thunk 调用一个动作时,我可以看到该动作被调用(使用 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

组件

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>
    )
  }
}

【问题讨论】:

    标签: reactjs typescript redux redux-thunk


    【解决方案1】:

    看起来你正在调度你的 thunk 动作,但你实际上并没有在 thunk 动作中调度一个动作。

    当您调度 getSearchResults(一个 thunk 操作)时,您将返回一个以 dispatch 方法作为参数的函数,您已经用 return (dispatch) =&gt; { 正确记录了这一点。您可以使用该调度方法来调度进一步的操作。

    您必须调用该调度方法才能使其生效。您可能想要在 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))
      }
    }
    

    然后您应该在 reducer 中收到 UPDATE_SEARCH_RESULTS 操作。

    如果您要在 API 调用中大量使用 redux 操作,我强烈建议您使用像 https://www.npmjs.com/package/redux-api-middleware 这样的中间件来保持干净。

    【讨论】:

    • 是的——没错,我还没有调度任何动作,因为调度中的代码没有被调用(第二个 console.log 没有运行)。感谢redux-api-middleware的推荐,我一定会去看看的。
    【解决方案2】:

    我发现像这样映射我的调度解决了我的问题 - 但我不是 100% 确定为什么...:

    const mapDispatchToProps = (dispatch: any, ownProps: OwnProps): DispatchProps => {
      return {
        getSearchResults: () => dispatch(getSearchResults()),
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-08-18
      • 2021-02-27
      • 2020-08-18
      • 2021-05-21
      • 2016-12-11
      • 2019-03-29
      • 2021-04-05
      • 2019-10-23
      • 2021-08-24
      相关资源
      最近更新 更多