【问题标题】:react-redux Unexpected Action Type Passed to React Action from React Class (Works Fine with React Component)react-redux 意外的动作类型从 React 类传递给 React 动作(适用于 React 组件)
【发布时间】:2016-12-03 05:14:53
【问题描述】:

我是 React 新手,我已经能够让 react-routerreact-reduxImmutable 一起工作。在我的一个组件文件中,我的 React 组件中有一个 handleItemClick() 方法,它按预期工作:

mortgage.js

import import React from "react";
import { connect } from 'react-redux';
import { changeActiveMenu } from '../actions/action';

class Mortgage extends React.Component {
    constructor(props) {
        super(props);
        this.handleItemClick = this.handleItemClick.bind(this);
    }
    handleItemClick (e, { name }) { //name reflects the routeName
        const activeItemProp = this.props.app.get('primaryMenuActiveItem');
        this.props.changeActiveMenu("test1", "test2");
    }

    render() {
        console.log("Route Name=[" +this.props.route.name +"]");
        console.log(this.props.app);
        const activeItemProp = this.props.app.get('primaryMenuActiveItem');
        return (
          <div>
            <h4>{activeItemProp}</h4>
            <button onClick={this.handleItemClick}>Send Action</button>
          </div>
        )
    }
}

export default connect(
    state => ({ app: state.get('app'),routing: state.get('routing') }),
    { changeActiveMenu }
)(Mortgage)

我的动作很简单:

action.js

export function changeActiveMenu(activeItem) {
  return {
    type: 'CHANGE_MENU',
    payload: {
      activeItem: activeItem
    }
  };
}

这是我的应用程序缩减器:

app_reducer.js

import Immutable from 'immutable';

const initialState = Immutable.Map({
  primaryMenuActiveItem: "overviewPrimary",
  secondaryMenuActiveItem: 'home'
});

export default (state = initialState, action) => {
      console.log("action.type=[" +action.type +"]");
    if (action.type === "CHANGE_MENU") { //use the change primaryMenuActiveItem and secondaryMenuActiveItem
    if(action.payload.activeItem.indexOf('Primary') >= 0) { //dealing with primaryMenu
      return state.merge({ //returning new state
        primaryMenuActiveItem: action.payload.activeItem
      })
    }
    else { //dealing with secondaryMenu
      return state.merge({ //returning new state
        secondaryMenuActiveItem: action.payload.activeItem
      })
    }
  }
  return state; //returns initial state
}

我从我的 app reducer 中的 console.log() 获得了预期的 action.type"CHANGE_MENU"

action.type=[CHANGE_MENU]

我的问题是当我尝试在我的 React 类中实现相同的代码时(main.js 中的第 6 行)。我从上面利用相同的操作和应用程序缩减程序文件。在我的 React 类中,它是我的 Main 组件的一部分:

ma​​in.js

import React from "react";
import { connect } from 'react-redux';
import { changeActiveMenu } from '../../actions/action';

const PrimaryMenu = React.createClass({
  handleItemClick (e, { name }) { //name reflects the routeName
     changeActiveMenu("primary", name);
   },
  renderMenu(menu) {

    //use primaryMenuActiveItem and secondaryMenuActiveItem
    const routingProp = this.props.routing.get('locationBeforeTransitions').get('pathname');
    console.log(routingProp);
    const primaryMenuActiveItem = routingProp === "/" ? 'overviewPrimary' : routingProp;
    console.log(primaryMenuActiveItem);

    return (
      <div id="primary-menu">
        <Menu pointing>
          <Link to={menu[0].routeName}><Menu.Item name={menu[0].routeName} active={primaryMenuActiveItem === menu[0].routeName} onClick={this.handleItemClick}>{menu[0].menuName}</Menu.Item></Link>
        </Menu>
      </div>
    )
  },
  render() {
    const menu = this.props.data;
    return (
      <div id="menu">
        {this.renderMenu(menu)}
      </div>
    )
  }
});

class Main extends React.Component {  
  render() {
    const {routing} = this.props;
    return (
      <div id="main">
        <PrimaryMenu app = {this.props.app } routing = {this.props.routing } data={primaryMenuList}/>
        {this.props.children}
      </div>
    )
  }
}

export default connect(
  state => ({ app: state.get('app'),routing: state.get('routing') }),
  { changeActiveMenu }
)(Main)

现在我的action.type如下:

action.type=[@@router/LOCATION_CHANGE]

我知道这与React class vs. component 有关。有任何想法吗?感谢所有帮助。

【问题讨论】:

    标签: reactjs react-router react-redux immutable.js


    【解决方案1】:

    您看到的日志@@router/LOCATION_CHANGE 大概是由 react-router 调度的操作。

    但我发现您的第二个实现存在问题。

    在第一个示例(extends React.component)中,您已将 @connected 导入操作 changeActiveMenuMortgage。所以在handleItemClick 中,您this.props.changeActiveMenu("test1", "test2") 的身份发送操作

    在第二个示例中(使用React.createClass),我看到您有两个组件。主菜单和主菜单。您有 @connected changeActiveMenu 到 Main,因此 Main 将其作为道具接收。然后在 PrimaryMenu 的handleItemClick 中,您将调用动作创建者changeActiveMenu("primary", name)

    您可能已经注意到以上两段中的粗体字。调用动作创建者和分派动作创建者是有区别的。

    思考要点:

    • 在 Redux 中,动作创建者是 return 带有 type 键的对象的函数。 type 是目标减速器。
    • 要触发目标reducer,动作创建者在被调用时应该用dispatch 包裹起来。

    所以在您的第二个示例中,您只是调用它,而不用 dispatch 包装它。当您在@connect 中使用mapDispatchToProps(我看到您使用了相同的简写,这很好)时,动作创建者基本上被dispatch 包裹,并作为道具传递给组件。

    所以你可以做的是:

    export default connect(
      state => ({ app: state.get('app'), routing: state.get('routing') }),
      { changeActiveMenu }
    )(PrimaryMenu)
    

    将状态键 approuting 连接到 Main 组件是没有意义的,因为 Main 不使用这些属性,而是将其传递给 PrimaryMenu。所以让@connect PrimaryMenu 上的所有内容。

    然后是 PrimaryMenu 的handleItemClick:

      handleItemClick (e, { name }) {
         this.props.changeActiveMenu("primary", name);
      }
    

    【讨论】:

    • 感谢@free-soul 的精彩文章。这确实帮助我解决了我的问题。你摇滚!
    猜你喜欢
    • 2023-03-13
    • 1970-01-01
    • 2020-08-16
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 2019-07-08
    相关资源
    最近更新 更多