react-redux 从 React Class 传递给 React Action 的意外操作类型(与 React 组件配合良好)
react-redux Unexpected Action Type Passed to React Action from React Class (Works Fine with React Component)
我是 React 的新手,我已经能够让 react-router
、react-redux
和 Immutable
一起工作。在我的一个组件文件中,我的 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
}
我从我的应用减速器中的 console.log()
获得了预期的 action.type
值 "CHANGE_MENU"
:
action.type=[CHANGE_MENU]
我的问题是当我尝试在我的 React class 中实现相同的代码时(main.js 中的第 6 行)。我利用上面相同的操作和应用程序缩减器文件。在我的 React Class 中,它是我的主要组件的一部分:
main.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
有关。有任何想法吗?感谢所有帮助。
您看到的日志 @@router/LOCATION_CHANGE
大概是 react-router 调度的一个动作。
但是我发现你的第二个实现有问题。
在第一个示例(extends React.component
)中,您@connect
编辑了导入操作 changeActiveMenu
到 Mortgage
。因此,在 handleItemClick
中,您 将操作 分派为 this.props.changeActiveMenu("test1", "test2")
.
在第二个示例中(使用 React.createClass
),我看到您有两个组件。主菜单和主菜单。您已 @connect
ed changeActiveMenu
到 Main,因此 Main 将其作为道具接收。然后在 PrimaryMenu 的 handleItemClick
中,您 调用 作为 changeActiveMenu("primary", name)
.
的动作创建者
您可能已经注意到上面两段中的粗体字。调用 action creator 和调度 action creator 是有区别的。
思考点:
- 在 Redux 中,动作创建者是
return
具有 type
键的对象的函数。 type
是目标减速器。
- 要触发目标 reducer,action creator 在被调用时应该用
dispatch
包裹起来。
所以在你的第二个例子中你只是调用它,没有用 dispatch
包装它。当你在 @connect
中 mapDispatchToProps
(我看到你使用了相同的缩写,这很好),动作创建者基本上用 dispatch
包装并作为道具传递给组件。
所以你可以做的是:
export default connect(
state => ({ app: state.get('app'), routing: state.get('routing') }),
{ changeActiveMenu }
)(PrimaryMenu)
将状态键 app
和 routing
连接到 Main 组件没有意义,因为 Main 除了将其传递给 PrimaryMenu 之外不使用这些道具。所以让 @connect
PrimaryMenu 上的所有内容。
然后是 PrimaryMenu 的 handleItemClick
:
handleItemClick (e, { name }) {
this.props.changeActiveMenu("primary", name);
}
我是 React 的新手,我已经能够让 react-router
、react-redux
和 Immutable
一起工作。在我的一个组件文件中,我的 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
}
我从我的应用减速器中的 console.log()
获得了预期的 action.type
值 "CHANGE_MENU"
:
action.type=[CHANGE_MENU]
我的问题是当我尝试在我的 React class 中实现相同的代码时(main.js 中的第 6 行)。我利用上面相同的操作和应用程序缩减器文件。在我的 React Class 中,它是我的主要组件的一部分:
main.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
有关。有任何想法吗?感谢所有帮助。
您看到的日志 @@router/LOCATION_CHANGE
大概是 react-router 调度的一个动作。
但是我发现你的第二个实现有问题。
在第一个示例(extends React.component
)中,您@connect
编辑了导入操作 changeActiveMenu
到 Mortgage
。因此,在 handleItemClick
中,您 将操作 分派为 this.props.changeActiveMenu("test1", "test2")
.
在第二个示例中(使用 React.createClass
),我看到您有两个组件。主菜单和主菜单。您已 @connect
ed changeActiveMenu
到 Main,因此 Main 将其作为道具接收。然后在 PrimaryMenu 的 handleItemClick
中,您 调用 作为 changeActiveMenu("primary", name)
.
您可能已经注意到上面两段中的粗体字。调用 action creator 和调度 action creator 是有区别的。
思考点:
- 在 Redux 中,动作创建者是
return
具有type
键的对象的函数。type
是目标减速器。 - 要触发目标 reducer,action creator 在被调用时应该用
dispatch
包裹起来。
所以在你的第二个例子中你只是调用它,没有用 dispatch
包装它。当你在 @connect
中 mapDispatchToProps
(我看到你使用了相同的缩写,这很好),动作创建者基本上用 dispatch
包装并作为道具传递给组件。
所以你可以做的是:
export default connect(
state => ({ app: state.get('app'), routing: state.get('routing') }),
{ changeActiveMenu }
)(PrimaryMenu)
将状态键 app
和 routing
连接到 Main 组件没有意义,因为 Main 除了将其传递给 PrimaryMenu 之外不使用这些道具。所以让 @connect
PrimaryMenu 上的所有内容。
然后是 PrimaryMenu 的 handleItemClick
:
handleItemClick (e, { name }) {
this.props.changeActiveMenu("primary", name);
}