如何避免 reactjs 中的 key/id 问题并使 props 从 parent 传递到 child?
how to avoid key/id problems in reactjs and make props pass from parent to child?
我在尝试将 parent 数据传递给 child 组件时总是碰壁。
我的看法:
<%= react_component 'Items', { data: @items } %>
我的 Items
组件进行 ajax 调用、设置状态并呈现 Item
。将 key={this.props.id}
排除在传递给映射函数的 Item
实例之外,以便组件 html 呈现到页面。但是添加密钥,我得到一个控制台错误:Uncaught TypeError: Cannot read property 'id' of undefined
这是'Items':
var Items = React.createClass({
loadItemsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
this.loadItemsFromServer();
},
render: function() {
var itemNodes = this.props.data.map(function() {
return (
<Item key={this.props.id} />
);
});
return (
<div className="ui four column doubling stackable grid">
{itemNodes}
</div>
);
}
});
我的 item.js.jsx 组件只是格式化每个 Item
:
var Item = React.createClass({
render: function() {
return (
<div className="item-card">
<div className="image">
</div>
<div className="description">
<div className="artist">{this.props.artist}</div>
</div>
</div>
);
}
});
React 开发工具扩展显示项目内的道具和状态数据。然而child仁是空的。
我知道 this,但我正在使用 this.props.id
设置密钥。我不确定我错过了什么?
您的实施存在一些问题。
首先,您需要决定:是否要从您的视图中呈现传递给 Items 组件的 @items?或者你想异步加载它们?
因为现在我得到的印象是你正在尝试两者都做...
呈现从视图传递的项目
如果您想呈现传递给组件的视图中的项目,请确保它是正确的 json。您可能需要对其调用 'as_json'。
<%= react_component 'Items', { data: @items.as_json } %>
然后,在您的组件中,映射项目以呈现 <Item />
组件。这是第二个问题,关于你的钥匙。您需要将 item 变量定义到您的 map 函数的回调函数,并从中读取 id:
var itemNodes = this.props.data.map(function(item) {
return (
<Item key={item.id} artist={item.artist} />
);
});
请注意,我还将作者添加为 prop,因为您在 <Item />
组件中使用了它。
您可以删除 componentDidMount
和 loadItemsFromServer
函数,因为您没有使用它们。
异步加载项目
如果您想异步加载项目,就像您在 loadItemsFromServer
函数中尝试做的那样,首先,从您的视图中传递 url 并删除 {data: @ items} 部分,因为您将从组件加载项目,例如:
<%= react_component 'Items', { url: items_path(format: :json) } %>
如果要呈现异步获取的项目,请使用:
var itemNodes = this.state.data.map(function(item) {
return (
<Item key={item.id} artist={item.artist} />
);loadItemsFromServer
});
请注意,我将 this.props.map
更改为 this.state.map
您现在可以使用 componentDidMount 和 loadItemsFromServer 函数加载数据并将它们保存到状态。
我在 Items
组件
中发现您发布的代码存在一些问题
- 您正在呈现
this.props.data
,而实际上 this.state.data
是使用 ajax 请求更新的那个。您需要渲染 this.state.data
但从 props
获取初始值
- map 迭代器函数接受一个表示当前数组元素的参数,使用它来访问属性而不是使用未定义的 this
更新后的代码应该如下所示
var Item = React.createClass({
render: function() {
return (
<div className="item-card">
<div className="image">
</div>
<div className="description">
<div className="artist">{this.props.artist}</div>
</div>
</div>
);
}
});
var Items = React.createClass({
getInitialState: function() {
return {
// for initial state use the array passed as props,
// or empty array if not passed
data: this.props.data || []
};
},
loadItemsFromServer: function() {
var data = [{
id: 1,
artist: 'abc'
}, {
id: 2,
artist: 'def'
}]
this.setState({
data: data
});
},
componentDidMount: function() {
this.loadItemsFromServer();
},
render: function() {
// use this.state.data not this.props.data,
// since you are updating the state with the result of the ajax request,
// you're not updating the props
var itemNodes = this.state.data.map(function(item) {
// the map iterator function takes an item as a parameter,
// which is the current element of the array (this.state.data),
// use (item) to access properties, not (this)
return (
// use key as item id, and pass all the item properties
// to the Item component with ES6 object spread syntax
<Item key={item.id} {...item} />
);
});
return (
<div className="ui four column doubling stackable grid">
{itemNodes}
</div>
);
}
});
我在尝试将 parent 数据传递给 child 组件时总是碰壁。
我的看法:
<%= react_component 'Items', { data: @items } %>
我的 Items
组件进行 ajax 调用、设置状态并呈现 Item
。将 key={this.props.id}
排除在传递给映射函数的 Item
实例之外,以便组件 html 呈现到页面。但是添加密钥,我得到一个控制台错误:Uncaught TypeError: Cannot read property 'id' of undefined
这是'Items':
var Items = React.createClass({
loadItemsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
this.loadItemsFromServer();
},
render: function() {
var itemNodes = this.props.data.map(function() {
return (
<Item key={this.props.id} />
);
});
return (
<div className="ui four column doubling stackable grid">
{itemNodes}
</div>
);
}
});
我的 item.js.jsx 组件只是格式化每个 Item
:
var Item = React.createClass({
render: function() {
return (
<div className="item-card">
<div className="image">
</div>
<div className="description">
<div className="artist">{this.props.artist}</div>
</div>
</div>
);
}
});
React 开发工具扩展显示项目内的道具和状态数据。然而child仁是空的。
我知道 this,但我正在使用 this.props.id
设置密钥。我不确定我错过了什么?
您的实施存在一些问题。
首先,您需要决定:是否要从您的视图中呈现传递给 Items 组件的 @items?或者你想异步加载它们? 因为现在我得到的印象是你正在尝试两者都做...
呈现从视图传递的项目
如果您想呈现传递给组件的视图中的项目,请确保它是正确的 json。您可能需要对其调用 'as_json'。
<%= react_component 'Items', { data: @items.as_json } %>
然后,在您的组件中,映射项目以呈现 <Item />
组件。这是第二个问题,关于你的钥匙。您需要将 item 变量定义到您的 map 函数的回调函数,并从中读取 id:
var itemNodes = this.props.data.map(function(item) {
return (
<Item key={item.id} artist={item.artist} />
);
});
请注意,我还将作者添加为 prop,因为您在 <Item />
组件中使用了它。
您可以删除 componentDidMount
和 loadItemsFromServer
函数,因为您没有使用它们。
异步加载项目
如果您想异步加载项目,就像您在 loadItemsFromServer
函数中尝试做的那样,首先,从您的视图中传递 url 并删除 {data: @ items} 部分,因为您将从组件加载项目,例如:
<%= react_component 'Items', { url: items_path(format: :json) } %>
如果要呈现异步获取的项目,请使用:
var itemNodes = this.state.data.map(function(item) {
return (
<Item key={item.id} artist={item.artist} />
);loadItemsFromServer
});
请注意,我将 this.props.map
更改为 this.state.map
您现在可以使用 componentDidMount 和 loadItemsFromServer 函数加载数据并将它们保存到状态。
我在 Items
组件
- 您正在呈现
this.props.data
,而实际上this.state.data
是使用 ajax 请求更新的那个。您需要渲染this.state.data
但从props
获取初始值
- map 迭代器函数接受一个表示当前数组元素的参数,使用它来访问属性而不是使用未定义的 this
更新后的代码应该如下所示
var Item = React.createClass({
render: function() {
return (
<div className="item-card">
<div className="image">
</div>
<div className="description">
<div className="artist">{this.props.artist}</div>
</div>
</div>
);
}
});
var Items = React.createClass({
getInitialState: function() {
return {
// for initial state use the array passed as props,
// or empty array if not passed
data: this.props.data || []
};
},
loadItemsFromServer: function() {
var data = [{
id: 1,
artist: 'abc'
}, {
id: 2,
artist: 'def'
}]
this.setState({
data: data
});
},
componentDidMount: function() {
this.loadItemsFromServer();
},
render: function() {
// use this.state.data not this.props.data,
// since you are updating the state with the result of the ajax request,
// you're not updating the props
var itemNodes = this.state.data.map(function(item) {
// the map iterator function takes an item as a parameter,
// which is the current element of the array (this.state.data),
// use (item) to access properties, not (this)
return (
// use key as item id, and pass all the item properties
// to the Item component with ES6 object spread syntax
<Item key={item.id} {...item} />
);
});
return (
<div className="ui four column doubling stackable grid">
{itemNodes}
</div>
);
}
});