我正在尝试在一个异步动作创建者中调度另一个动作。但是,当我使用redux-thunk中间件提供的调度功能时,会抛出Uncaught TypeError: dispatch is not a function错误。

以下是更多帮助的文件

store / store.dev.js

use strict';

import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from '../reducers';
import ReduxThunk from 'redux-thunk';

export default function configureStore(initialState = {}) {
const store = createStore(rootReducer, initialState, applyMiddleware(ReduxThunk));
  console.log('store returned', store);
return store;
}


src / index.js

'use strict';

import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { hydrate } from 'react-dom';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import configureStore from './store';
import App from './containers/App.js';
import routes from './routes/index.js';

hydrate(
  <Provider store={configureStore()}>
    <BrowserRouter>
      {renderRoutes(routes)}
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
);


减速器

'use strict';

import { LOGIN_SUBMITTED, LOGIN_COMPLETED } from '../constants/ActionTypes.js';

const loginSubmitReducer = (state = [], action) => {
  console.log('in reducer');
    switch (action.type) {

      case LOGIN_SUBMITTED:
      console.log('login submitted case');
        return Object.assign({}, state, {
          loginSubmitted: true
        });

      case LOGIN_COMPLETED:
      console.log('login completed case');
        return Object.assign({}, state, {
          loginCompleted: true
        });

      default:
      console.log('in default case');
        return {
          a:1
        };
    }
}

export default loginSubmitReducer;


容器/App.js

'use strict';

import React from 'react';
import { loginCompleted, loginSubmitted } from '../actions';
import { createStructuredSelector, createSelector } from 'reselect';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Header, ButtonDemo, LoginForm } from '../components';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';

class App extends React.Component {
  constructor(props, context) {
    super(props);
    this.state = {
      appState: {
        entry: 'yes'
      }
    }

    console.log('props in App constructor', props);
    console.log('context in App constructor', context);

    this.newFunc = this.newFunc.bind(this);
  }
  newFunc () {
    console.log('props', this.props);
  }
  render() {
    console.log('props in main App', this.props);
    console.log('Actions', this.props.actions);
    console.log('context in App', this.context);
    // this.props.actions.loginCompleted();
    const muiTheme = getMuiTheme({
      lightBaseTheme
    });

    return (
      <MuiThemeProvider muiTheme={muiTheme}>
        <div>
            <Header />
            <LoginForm
              appstate = {this.props.appState}
              dispatchAction = {this.props.actions}
            />
        </div>
      </MuiThemeProvider>
    );
  }
}

// const mapStateToProps = createStructuredSelector({});
const mapStateToProps = (state) => {
  return { appState: state.loginSubmitReducer };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({ loginCompleted, loginSubmitted }, dispatch)
  };
  // dispatch(loginCompleted());
}

export default connect(mapStateToProps, mapDispatchToProps)(App);


组件

    'use strict';

import React, { PropTypes } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import ContentAdd from 'material-ui/svg-icons/content/add';
import { loginAction } from '../actions';
// import '../css/style.css';


class LoginForm extends React.Component {
    constructor(props) {
        super(props);
        this.loginSubmit = this.loginSubmit.bind(this);
    }

    loginSubmit() {
        console.log('Login fomr submitted', this.props);
        console.log('loginAction', loginAction);
        loginAction()();
    }

    render () {
        console.log('props when login rendered', this.props);
        return (
            <div className="loginForm">
                <div className="title">LOGIN</div>
                <form>
                    <TextField
                        hintText="Username"
                        floatingLabelText="Username"/><br/>
                    <br/>
                    <TextField
                        hintText="Password"
                        type="Password"
                        floatingLabelText="Password"/><br/>
                    <br/>
                    <RaisedButton
                        label="Login"
                        secondary={true}
                        onClick={this.loginSubmit}
                        className="submitBtn" /><br/>
                    <br/>
                    <FloatingActionButton
                        secondary={true}
                        className="registerBtn">
                        <ContentAdd />
                    </FloatingActionButton>
                </form>
            </div>
        )
    }
}

export default LoginForm;


动作/登录Action.js

'use strict';

// import { polyfill } from 'es6-promise';
// require('es6-promise').polyfill();
// require('isomorphic-fetch');
import request from 'superagent';
// import fetch from 'isomorphic-fetch';
import loginCompleted from './loginCompletedAction.js';
import loginSubmitted from './loginSubmittedAction.js';

const loginAction = (dispatch) => {
    console.log('validateUserLogin executed', this);
    console.log('validateUserLogin dispatch', dispatch);
    return (dispatch) => {
        // console.log('first return', dispatch);
        // this.props.dispatch(loginSubmitted());
        // this.props.dispatchAction.loginSubmitted();
        dispatch(loginSubmitted());

        request.get('http://localhost:3000/loginSubmit')
            .end((err, res) => {
                console.log('res', res);
                console.log('err', err);
                // this.props.dispatchAction.loginCompleted();
            });
    }
}

export default loginAction;


资料夹结构

javascript - 未在异步操作创建者中定义调度-LMLPHP

我正在使用redux-thunk中间件,该中间件将分派功能公开给异步操作创建者。仍然不起作用。

请帮忙!

最佳答案

动作创建者的第一个参数不应为dispatch,而应传递给动作创建者的参数。

const loginAction = () => (dispatch) => {
    console.log('validateUserLogin executed', this);
    console.log('validateUserLogin dispatch', dispatch);
    // console.log('first return', dispatch);
    // this.props.dispatch(loginSubmitted());
    // this.props.dispatchAction.loginSubmitted();
    dispatch(loginSubmitted());

    request.get('http://localhost:3000/loginSubmit')
        .end((err, res) => {
            console.log('res', res);
            console.log('err', err);
            // this.props.dispatchAction.loginCompleted();
        });
}


编辑
作为您的评论的后续部分,首先,我认为您没有将redux-thunk正确地实现为中间件,但是根据您的代码,它看起来还可以。
然后我注意到您并不是真正在调度loginAction而是在调用它。
您应该将其发送dispatch(loginAction())。您的组件应连接到redux,然后您将可以访问dispatch

10-06 08:35