【问题标题】:React/Redux dispatch not triggering reducerReact/Redux 调度未触发减速器
【发布时间】:2017-10-18 11:11:34
【问题描述】:

努力从我的 React 组件调度一个动作。这是我的第一个 Redux 应用程序。一切似乎都运行良好,但如果是这样,我不会发布这个问题。我正在使用 Redux devTool 来调试我的应用程序。如果我使用 devTools 中的调度程序,我的减速器将毫无问题地触发。但是,我无法从我的 React 组件中发送相同的操作。我在我的操作中添加了一个断点以查看它是否被触发。我肯定是并且它还返回一个有效的操作(类型和有效负载)。这是我的代码:

store.js

import {createStore, applyMiddleware, compose} from 'redux'
import {createLogger} from 'redux-logger'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import reducers from './reducers/index'

const logger = createLogger()

const store = createStore(
    reducers,
    window.__REDUX_DEVTOOLS_EXTENSION__ && 
    window.__REDUX_DEVTOOLS_EXTENSION__(),
    compose(
      applyMiddleware(thunk, promise, logger)
    )
)

export default store

reducers (index.js)

import {combineReducers} from 'redux'
import userReducer from './userReducer'

const allReducers = combineReducers({
    user: userReducer
})

export default allReducers

client.js

import React from 'react'
import ReactDOM from 'react-dom'
import {Provider} from 'react-redux'
import store from './store'
import Router from './modules/router'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import getMuiTheme from 'material-ui/styles/getMuiTheme'
import CustomTheme from './modules/theme'
import injectTapEventPlugin from 'react-tap-event-plugin'
require('../scss/style.scss')

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();

ReactDOM.render(
  <Provider store={store}>
    <MuiThemeProvider muiTheme={CustomTheme}>
      <Router/>
    </MuiThemeProvider>
  </Provider>,
  document.getElementById('app')
);

userReducer.js

export default function (state = {loggedIn: false}, action) {
    console.log("THIS IS THE REDUCER: STATE: ", state, " - ACTION: ", action)
    switch (action.type) {
        case 'LOGIN':
            return {...state, loggedIn: action.payload}
    }
    return state;
}

userActions.js

export const login = () => {
  console.log("TEST")
    return {
        type: 'LOGIN',
        payload: true
    }
}

login.js

import React from 'react'
import ReactDOM from 'react-dom'
import LoginForm from '../containers/loginform'

class Login extends React.Component {
  render() {
    return (
      <LoginForm/>
    )
  }
}

export default Login

loginform.js

import React, {PropTypes} from 'react'
import ReactDOM from 'react-dom'
import {Redirect} from 'react-router-dom'
import {connect} from 'react-redux'
import {login} from '../actions/userActions'
import RaisedButton from 'material-ui/RaisedButton'
import TextField from 'material-ui/TextField'

class LoginForm extends React.Component {
  constructor(props) {
    super(props)
  }
  loginReq(e){
     e.preventDefault()
     this.props.login()
  }
  render() {
    return (
      <div>
        <form className='login-form-container' onSubmit=    {this.loginReq.bind(this)}>
          <div className='login-form-row'>
            <TextField
              ref='email'
              hintText='Email'
              floatingLabelText='Email'
              className='login-form-field'/>
          </div>
          <div className='login-form-row'>
            <TextField
              ref='password'
              hintText='Password'
              floatingLabelText='Password'
              type='password'
              className='login-form-field'/>
          </div>
          <div className='login-form-row'>
            <RaisedButton
              type= 'submit'
              label='Login'
              className='login-form-button'/>
          </div>
        </form>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
    return {
        loggedIn: state.user.loggedIn
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
      login: () => dispatch(login())
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginForm)

请您给我一些指导,让我了解如何调试以找出此调度不起作用的原因。我尝试将操作对象直接添加到该调度函数中。仍然没有运气。我在控制台中没有任何错误。我的 console.logs 仅在视图呈现和单击登录提交按钮时打印。

Console Screenshot

【问题讨论】:

  • 你检查过控制台是否有错误吗?您的代码似乎是正确的。
  • 我不确定它是否真的与您的调度问题有关,但您的createStore 呼叫中似乎有错误。 Redux DevTools Extension 增强器应该是对compose() 的调用的一部分,在applyMiddleware() 之后。
  • 另一个建议:虽然您的mapDispatch 用法看起来正确,但只是为了好玩,请尝试使用其他方式绑定动作创建者:export default connect(mapStateToProps, {login})(LoginForm)。如果这不起作用,我建议您访问 Discord 上的 Reactiflux 聊天频道并寻求帮助。邀请链接在reactiflux.com

标签: reactjs redux react-redux


【解决方案1】:

终于找到了我的问题。我的中间件实现导致了这个问题。我错误地传递了promise。应该是:

import {createStore, applyMiddleware} from 'redux'
import {composeWithDevTools} from 'redux-devtools-extension'
import {createLogger} from 'redux-logger'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import reducers from './reducers/index'

const logger = createLogger()

const middleware = applyMiddleware(promise(), logger, thunk)

const store = createStore(reducers, composeWithDevTools(middleware))

export default store

还发现 redux-devtools-extension 对于 Redux devTools 来说更干净。

【讨论】:

    【解决方案2】:

    我的预感是您尝试调用函数以调度操作的方式。首先,将函数绑定到组件构造函数中的this(有关更多信息,请参阅事件处理程序here 的React 文档)。其次,只需将函数传递给onSubmit

    class LoginForm extends React.Component {
      constructor(props) {
        super(props)
        this.loginReq = this.loginReq.bind(this);
      }
    
      loginReq(e) {
        e.preventDefault()
        this.props.login()
      }
    
      render() {
        return (
          <div>
            <form className='login-form-container' onSubmit={this.loginReq}>
              <div className='login-form-row'>
                <TextField
                  ref='email'
                  hintText='Email'
                  floatingLabelText='Email'
                  className='login-form-field'/>
              </div>
              <div className='login-form-row'>
                <TextField
                  ref='password'
                  hintText='Password'
                  floatingLabelText='Password'
                  type='password'
                  className='login-form-field'/>
              </div>
              <div className='login-form-row'>
                <RaisedButton
                  type= 'submit'
                  label='Login'
                  className='login-form-button'/>
              </div>
            </form>
          </div>
        )
      }
    }
    

    将函数绑定到this 的另一种方法是删除构造函数中的绑定语句并为表单道具使用箭头函数,如下所示:

    onSubmit={e => this.loginReq(e)}
    

    【讨论】:

    • 嗨迈克尔,谢谢你的知识分享。不幸的是,它仍然无法正常工作。这应该很简单。开始有点沮丧。我看过很多视频,看来我的实现应该可以了。我什至尝试在调度函数中对操作进行硬编码,但它仍然没有触发我的减速器。不确定如何调试从我的操作到我的减速器的连接,因为我的操作功能肯定会被触发。
    • 您的事件处理程序是否在链上的每个阶段都被调用?有什么例外吗?如果你有一个调试器,那么从点击按钮到点击减速器的每一步都要断点。如果调试器失败,请在您认为代码应该执行的每个阶段都使用老式的 console.log。我不熟悉 Redux Dec 工具扩展,但我也倾向于将您的商店创建回归基础并进行构建。你能做一个小的独立准系统 Redux 示例来确保你能以这种方式工作吗?
    【解决方案3】:

    修改动作:

    export const login = () => {
      return function (dispatch) {
        console.log('here');
        dispatch({
            type: 'LOGIN',
            payload: true
        });
      }
    }
    

    我猜你在这种情况下会喜欢 => 语法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-31
      • 2018-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多