ReactJS parent/child 列表项目在删除项目后无法正确呈现
ReactJS parent/child list items not rendering properly after an item is removed
示例:https://jsfiddle.net/wbellman/ghuw2ers/6/
在我正在处理的应用程序中,我有一个父容器(在我的示例中为 List),其中包含一个子项列表(在我的示例中为 Hero)。该列表由外部对象管理。为了简单起见,我直接在 JS 中声明了对象。 (在我的实际应用程序中,数据存储已正确命名空间等等。)
我遇到的问题是列表中有三个元素,如果我从中间删除一个项目,呈现的列表似乎会删除最后一个元素。然而,外部对象反映了正确的列表。
例如:
- 我的列表包含元素:队长、雷神、绿巨人
- 如果删除 "thor",将呈现 "cap" 和 "thor"
- heroList 反映了 "cap" 和 "hulk"
我对 ReactJs 比较陌生,所以我的前提很有可能存在根本性缺陷。
注意:该示例反映了一个复杂得多的应用程序。出于演示目的,它的结构类似。我知道你可以做一个单一的组件,但在实际的应用程序中是不实用的。
如有任何帮助,我们将不胜感激。
这是来自 JSFiddle 的代码:
var heroList = [
{ name: "cap" },
{ name: "thor"},
{ name: "hulk"}
];
var List = React.createClass({
getInitialState() {
console.log("heros", heroList);
return {
heros: heroList
};
},
onChange(e){
this.setState({heros: heroList});
},
removeHero(i,heros){
var hero = heros[i];
console.log("removing hero...", hero);
heroList = _.filter(heroList, function(h){ return h.name !== hero.name;});
this.setState({heros:heroList});
},
render() {
var heros = this.state.heros;
var createHero = (hero,index) => {
return <Hero hero={hero} key={index} onRemove={this.removeHero.bind(this,index,heros)}/>;
};
console.log("list", heros);
return (
<ul>
{heros.map(createHero)}
</ul>
)
}
});
var Hero = React.createClass({
getInitialState() {
return {
hero: this.props.hero
}
},
render() {
var hero = this.state.hero;
return (
<li>Hello {hero.name} | <button type="button" onClick={this.props.onRemove}>-</button></li>
);
}
});
ReactDOM.render(
<List />,
document.getElementById('container')
);
附加:我在从 JSFiddle 复制代码时遇到问题,我不小心破坏的任何东西都应该在这个问题顶部列出的 JSFiddle 中工作。
编辑:
根据 madox2, nicole, nuway and Damien Leroux 的评论,我最终做了以下事情:
https://jsfiddle.net/wbellman/ghuw2ers/10/
我希望有一种方法可以让每个人都得到信任,你们都帮了大忙。
将您的英雄 class 更改为此解决了为我显示错误的英雄名称的问题:
var Hero = React.createClass({
render() {
return (
<li>Hello {this.props.hero.name} | <button type="button" onClick={this.props.onRemove}>-</button></li>
);
}
});
即我从 class 中删除了本地状态并直接使用了 prop。
一般来说,尽量只在真正需要的时候使用本地商店。尝试将您的组件视为无状态的,即它们通过 props 获取某些东西并显示它,仅此而已。
按照这些思路,您也应该考虑通过道具将英雄列表传递给您的列表组件。
问题出在使用的键上。由于密钥是从索引中获取的,因此该密钥已被使用,因此显示了具有该密钥的英雄。
将其更改为 key={Math.random() * 100}
即可生效
如果您在管理数据方面确实遇到问题,您应该使用 Flux 或 Redux。
在此代码中:
heroList = _.filter(heroList, function(h){ return h.name !== hero.name;});
我只是不明白为什么你提交 heroList
而不是 this.state.heros
?每次添加或删除英雄时,当前作用域中的 heroList 不应该保持状态吗?全局 heroList
只是初始状态。
示例:https://jsfiddle.net/wbellman/ghuw2ers/6/
在我正在处理的应用程序中,我有一个父容器(在我的示例中为 List),其中包含一个子项列表(在我的示例中为 Hero)。该列表由外部对象管理。为了简单起见,我直接在 JS 中声明了对象。 (在我的实际应用程序中,数据存储已正确命名空间等等。)
我遇到的问题是列表中有三个元素,如果我从中间删除一个项目,呈现的列表似乎会删除最后一个元素。然而,外部对象反映了正确的列表。
例如:
- 我的列表包含元素:队长、雷神、绿巨人
- 如果删除 "thor",将呈现 "cap" 和 "thor"
- heroList 反映了 "cap" 和 "hulk"
我对 ReactJs 比较陌生,所以我的前提很有可能存在根本性缺陷。
注意:该示例反映了一个复杂得多的应用程序。出于演示目的,它的结构类似。我知道你可以做一个单一的组件,但在实际的应用程序中是不实用的。
如有任何帮助,我们将不胜感激。
这是来自 JSFiddle 的代码:
var heroList = [
{ name: "cap" },
{ name: "thor"},
{ name: "hulk"}
];
var List = React.createClass({
getInitialState() {
console.log("heros", heroList);
return {
heros: heroList
};
},
onChange(e){
this.setState({heros: heroList});
},
removeHero(i,heros){
var hero = heros[i];
console.log("removing hero...", hero);
heroList = _.filter(heroList, function(h){ return h.name !== hero.name;});
this.setState({heros:heroList});
},
render() {
var heros = this.state.heros;
var createHero = (hero,index) => {
return <Hero hero={hero} key={index} onRemove={this.removeHero.bind(this,index,heros)}/>;
};
console.log("list", heros);
return (
<ul>
{heros.map(createHero)}
</ul>
)
}
});
var Hero = React.createClass({
getInitialState() {
return {
hero: this.props.hero
}
},
render() {
var hero = this.state.hero;
return (
<li>Hello {hero.name} | <button type="button" onClick={this.props.onRemove}>-</button></li>
);
}
});
ReactDOM.render(
<List />,
document.getElementById('container')
);
附加:我在从 JSFiddle 复制代码时遇到问题,我不小心破坏的任何东西都应该在这个问题顶部列出的 JSFiddle 中工作。
编辑:
根据 madox2, nicole, nuway and Damien Leroux 的评论,我最终做了以下事情:
https://jsfiddle.net/wbellman/ghuw2ers/10/
我希望有一种方法可以让每个人都得到信任,你们都帮了大忙。
将您的英雄 class 更改为此解决了为我显示错误的英雄名称的问题:
var Hero = React.createClass({
render() {
return (
<li>Hello {this.props.hero.name} | <button type="button" onClick={this.props.onRemove}>-</button></li>
);
}
});
即我从 class 中删除了本地状态并直接使用了 prop。
一般来说,尽量只在真正需要的时候使用本地商店。尝试将您的组件视为无状态的,即它们通过 props 获取某些东西并显示它,仅此而已。
按照这些思路,您也应该考虑通过道具将英雄列表传递给您的列表组件。
问题出在使用的键上。由于密钥是从索引中获取的,因此该密钥已被使用,因此显示了具有该密钥的英雄。
将其更改为 key={Math.random() * 100}
即可生效
如果您在管理数据方面确实遇到问题,您应该使用 Flux 或 Redux。
在此代码中:
heroList = _.filter(heroList, function(h){ return h.name !== hero.name;});
我只是不明白为什么你提交 heroList
而不是 this.state.heros
?每次添加或删除英雄时,当前作用域中的 heroList 不应该保持状态吗?全局 heroList
只是初始状态。