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 中声明了对象。 (在我的实际应用程序中,数据存储已正确命名空间等等。)

我遇到的问题是列表中有三个元素,如果我从中间删除一个项目,呈现的列表似乎会删除最后一个元素。然而,外部对象反映了正确的列表。

例如:

我对 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 只是初始状态。