Redux 状态不会随着动作调度而更新

Posted

技术标签:

【中文标题】Redux 状态不会随着动作调度而更新【英文标题】:Redux state doesn't update with action dispatch 【发布时间】:2017-05-19 10:19:17 【问题描述】:

我已经浏览了我可以找到的所有文档和示例项目,用于使用 redux 和 react-router 构建一个 react 应用程序,但我似乎无法弄清楚如何让我的 redux 状态在我更新时调度动作。正如您在此屏幕截图中看到的,动作正在正确调度,但我的 store/nextState 没有更新。

动作:

export function updateUsername(username) 
  return  type: types.UPDATE_USERNAME, username ;

REDUCER(编辑:我已经尝试了这两种变体):

   /* first variation */
   const username = (
      state = '',
      action,
    ) => 
      switch (action.type) 
        case types.UPDATE_USERNAME:
          return Object.assign(, state, 
            username: action.username,
          );
        default:
          return state;
      
    ;

  /* second variation */
  const username = (
    state = '',
    action,
  ) => 
    switch (action.type) 
      case types.UPDATE_USERNAME:
        return action.username;
      default:
        return state;
    
  ;

减速机组合:

const user = combineReducers(
  isAuthenticated,
  token,
  password,
  username,
);

export default user;

REDUCERS/INDEX.JS:

const rootReducer = combineReducers(
  isFetching,
  open,
  search,
  user,
  routing: routerReducer,
);

export default rootReducer;

商店配置:

import React from 'react';
import  createStore, compose, applyMiddleware  from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import  routerMiddleware  from 'react-router-redux';
import rootReducer from '../reducers';
import * as actions from '../actions';

function configureStore(history, initialState) 
  const loggerMiddleware = createLogger();

  const enhancer = window.__REDUX_DEVTOOLS_EXTENSION__ &&
    window.__REDUX_DEVTOOLS_EXTENSION__();

  const store = createStore(
    rootReducer,
    initialState,
    compose(
      applyMiddleware(
        thunkMiddleware,
        loggerMiddleware,
        routerMiddleware(history),
      ),
      enhancer,
    ),
  );

  if (module.hot) 
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => 
      const nextReducer = rootReducer;
      store.replaceReducer(nextReducer);
    );
  

  return store;


export default configureStore;

商店创建:

const initialState = ;

const store = configureStore(browserHistory, initialState);
const history = syncHistoryWithStore(browserHistory, store);
const routes = createRoutes(store);


render(
  <Provider store=store>
      <Router history=history routes=routes />
  </Provider>,
  document.getElementById('root'),
);

最后是组件:

import React,  Component, PropTypes  from 'react';
import  connect  from 'react-redux';
import  bindActionCreators  from 'redux';
import TextField from 'material-ui/TextField';
import validator from 'validator';
import className from 'classnames';
import  Link  from 'react-router';
import * as AuthActions from '../../actions/AuthActions';

class LoginForm extends Component 
  constructor(props) 
    super(props);
    this.handleUsernameChange = this.handleUsernameChange.bind(this);
    this.handlePasswordChange = this.handlePasswordChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  

  handleUsernameChange(e) 
    this.props.actions.updateUsername(validator.escape(e.target.value.trim()));
  

  handlePasswordChange(e) 
    this.props.actions.updatePassword(validator.escape(e.target.value.trim()));
  

  handleSubmit(e, getState) 
    e.prevent.default();
    const user =  username: this.props.user.username, password: this.props.user.password ;
    console.log(user);
    this.props.actions.loginUser(user);
  

  render() 
    return (
          <form autoComplete="off" onSubmit=this.handleSubmit className='login-form'>
            <TextField
              type="username"
              autoFocus="true"
              floatingLabelText="Username"
              floatingLabelFixed=true
              autoComplete="off"
              onChange=this.handleUsernameChange
              />
            <br/>
            <TextField
              type="password"
              autoFocus="true"
              floatingLabelText="Password"
              floatingLabelFixed=true
              autoComplete="off"
              onChange=this.handlePasswordChange
              />
          </form>
    );
  


function mapStateToProps(state) 
  return 
    user: state.user,
  ;


function mapDispatchToProps(dispatch) 
  return 
    actions: bindActionCreators(AuthActions, dispatch),
  ;



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

我已经坚持了一周了,因此非常感谢您提供的任何帮助!谢谢!

【问题讨论】:

这些代码正确吗?您在日志中显示 UPDATE_USERNAME...但提供的操作代码是 UPDATE_PASSWORD 好收获。只需复制/粘贴错误的操作。已编辑! 你能提供一个 repo 以便我可以克隆和运行吗? @LucasKatayama 我会整理一个你可以在早上克隆的 repo。在那之前,我通过为我的每个 reducer 声明“return state = action.username”找到了一种解决方法。不理想,但它正在工作。 【参考方案1】:

我没有运行你的代码,所以我不能随便说如果这能解决它,但是你的用户名reducer返回一个带有username属性的对象,而它应该返回action.username字符串.

const username = (state = '', action) => 
  switch (action.type) 
    case types.UPDATE_USERNAME:
      return action.username
    default:
      return state;
  
;

另外,您是否确认您的types 声明中没有错字?我看到在你的减速器中你引用了types.UPDATE_USERNAME,但是在你的动作创建器中你使用字符串UPDATE_USERNAME来设置类型。

【讨论】:

不幸的是,我已经为reducer 尝试了这种格式,以及许多其他变体。似乎都没有工作。至于类型声明,我在 reducer 文件中导入了“* as types”。我现在试试切换。 您是否将console.log 放入您的username 减速器以确保它被调用? (或者只是在开发工具中添加了一个断点) 是的,它正在发射。当我发送登录操作时,我的后端授权服务也收到了 200,但同样的问题是 nextState 没有更新。 好吧,我还是什么都没看到。您是否尝试过使用调试器单步执行 combineReducers 返回的减速器? github.com/reactjs/redux/blob/v3.6.0/src/… 这应该会验证所有 reducer 函数的返回值。 你应该保持状态可变。设置为“state=something”可以改变应用程序的整个状态。相反,它应该从减速器返回状态为“return Object.assign(, state, action);”

以上是关于Redux 状态不会随着动作调度而更新的主要内容,如果未能解决你的问题,请参考以下文章

在通过动作调度进行状态更新后,在 React 中使用 Redux 执行函数?

Next js 应用刷新时,useEffect 不调度 redux saga 动作并更新状态

调度操作后 Redux 状态未更新

如何响应 redux 中的状态变化并派发另一个动作?

React,redux 组件不会在路由更改时更新

在消费者之外更新反应上下文?