2017-10-06 65 views
1

我想在一個異步動作創建者內部調度另一個動作。但是,當我使用redux-thunk中間件提供的調度功能時,會出現Uncaught TypeError: dispatch is not a function錯誤。調度沒有在異步動作創建者內部定義

下面是更多的幫助文件

店/ 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; 

動作/ loginAction.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; 

Project structure

我使用redux-thunk中間件暴露調度功能,以異步動作的創造者文件夾結構。它仍然不起作用。

請幫忙!

+0

這是導致錯誤的行嗎? 'loginAction()();'我認爲你需要從props(由'mapDispatchToProps()填充)'獲得'loginAction''而不是將它導入你的組件。當你直接導入它時,它不會被包裝,所以'dispatch()'不會被傳入。如果不是這條線,請告訴我們哪條線導致錯誤!這是非常重要的信息。 – stone

+0

@skypecakes - 'dispatch(loginSubmitted());'在'actions/loginAction.js'中導致錯誤。 – Sourav

+0

好的,但是從loginAction()調用?如果是這樣,你顯然不會傳遞'dispatch',但它期望你。 – stone

回答

1

您的動作創建者的第一個參數不應該是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(); 
     }); 
} 

編輯
作爲後續行動,以您的評論,IAT開始我還以爲你是不是正確地實施該redux-thunk作爲中間件,但根據您的代碼看起來OK。
然後我注意到你並不是真的調度loginAction,而只是調用它。
您應該發送它dispatch(loginAction())。你的組件應該連接到redux,那麼你將有權訪問dispatch

+0

這沒有任何區別。我已經刪除了調度參數,仍然會拋出相同的錯誤。 @ Sag1v – Sourav

+0

看完整的例子,這是你的動作創造者的樣子嗎? –

+0

是的,完全一樣。我從行動中刪除了參數 – Sourav

相關問題