我搜索过,所有问题都与How to pass props to {this.props.children}
有关但我的情况不同,
我将App
填入初始数据nodes
,并将nodes
映射到TreeNode
列表,我希望每个TreeNode
都具有传入的属性node
。
伪代码:
App.render:
{nodes.map(node =>
<TreeNode key={node.name} info={node} />
)}
TreeNode.render:
const { actions, nodes, info } = this.props
return (
<a>{info.name}</a>
);
似乎节点不能作为信息传入,日志显示信息未定义。
warning.js?8a56:45 Warning: Failed propType: Required prop `info` was not specified in `TreeNode`. Check the render method of `Connect(TreeNode)`.
TreeNode.js?10ab:57 Uncaught TypeError: Cannot read property 'name' of undefined
下面只是一个更完整的代码与这个问题有关(我认为商店和行动关系不大):
容器/ App.js:
import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Footer from '../components/Footer';
import TreeNode from '../containers/TreeNode';
import Home from '../containers/Home';
import * as NodeActions from '../actions/NodeActions'
export default class App extends Component {
componentWillMount() {
// this will update the nodes on state
this.props.actions.getNodes();
}
render() {
const { nodes } = this.props
console.log(nodes)
return (
<div className="main-app-container">
<Home />
<div className="main-app-nav">Simple Redux Boilerplate</div>
<div>
{nodes.map(node =>
<TreeNode key={node.name} info={node} />
)}
</div>
<Footer />
</div>
);
}
}
function mapStateToProps(state) {
return {
nodes: state.opener.nodes
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(NodeActions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
容器/ TreeNode.js
import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import classNames from 'classnames/bind'
import * as NodeActions from '../actions/NodeActions'
class TreeNode extends Component {
handleClick() {
this.setState({ open: !this.state.open })
if (this.state.open){
this.actions.getNodes()
}
}
render() {
const { actions, nodes, info } = this.props
if (nodes) {
const children =<div>{nodes.map(node => <TreeNode info={node} />)}</div>
} else {
const children = <div>no open</div>
}
return (
<div className={classNames('tree-node', { 'open':this.props.open})} onClick={ () => {this.handleClick()} }>
<a>{info.name}</a>
{children}
</div>
);
}
}
TreeNode.propTypes = {
info:PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
}
function mapStateToProps(state) {
return {
open: state.open,
info: state.info,
nodes: state.nodes
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(NodeActions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TreeNode);
减速器/ TreeNodeReducer.js
import { OPEN_NODE, CLOSE_NODE, GET_NODES } from '../constants/NodeActionTypes';
const initialState = {
open: false,
nodes: [],
info: {}
}
const testNodes = [
{name:'t1',type:'t1'},
{name:'t2',type:'t2'},
{name:'t3',type:'t3'},
]
function getFileList() {
return {
nodes: testNodes
}
}
export default function opener(state = initialState, action) {
switch (action.type) {
case OPEN_NODE:
var {nodes} = getFileList()
return {
...state,
open:true,
nodes:nodes
};
case CLOSE_NODE:
return {
...state,
open:false
};
case GET_NODES:
var {nodes} = getFileList()
return {
...state,
nodes:nodes
};
default:
return state;
}
}
有关完整代码,请参阅我的github https://github.com/eromoe/simple-redux-boilerplate
这个错误让我很困惑。我看到的是我父母已经有了一些孩子,然后使用react.Children
向他们提供道具,他们不使用redux。
答案 0 :(得分:1)
这是因为您正在从父Redux连接组件中渲染Redux连接组件,并尝试将props作为状态传递给它。
为什么TreeNode.js需要连接到Redux?道具/动作应该单向传递,只有顶层组件连接到状态,所有子组件基本上都是哑组件。
TreeNode应该与此类似:
class TreeNode extends Component {
handleClick() {
this.setState({ open: !this.state.open })
if (this.state.open){
this.props.actions.getNodes();
}
}
render() {
const { nodes, info } = this.props
if (nodes) {
const children =<div>{nodes.map(node => <TreeNode info={node} />)}</div>
} else {
const children = <div>no open</div>
}
return (
<div className={classNames('tree-node', { 'open':this.props.open})} onClick={ () => {this.handleClick()} }>
<a>{info.name}</a>
{children}
<div>{nodes.map(node => <TreeNode info={node} />)}</div>
</div>
);
}
}
TreeNode.propTypes = {
info: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
}
export default class TreeNode;
并且父组件将像这样呈现TreeNode,将props传递给组件:
<div>
{nodes.map(node =>
<TreeNode key={node.name} info={node} actions={this.props.actions} />
)}
</div>
答案 1 :(得分:1)
在循环nodes
值时,您拨打TreeNode
并提供属性info
:这很好!
但是当渲染组件时,会调用此函数:
function mapStateToProps(state) {
return {
open: state.open,
info: state.info,
nodes: state.nodes
};
}
如您所见,道具info
将使用state.info
中的值覆盖。我认为state.info
值为undefined
。所以React警告你TreeNode
需要这个值。此警告来自组件配置:
TreeNode.propTypes = {
info:PropTypes.object.isRequired
}
为什么state.info
未定义?我认为你并没有像现在这样称呼它。你应该致电state['reducerNameSavedWhenCreatingReduxStore
]。info to retreive
{}`。
你不应该通过ThreeNode
和props
填写connect()
。 sprintf
。