2016-05-20 5 views
1

Пример:ReactJS список родитель/ребенок элементы не отображается правильно после того, как элемент удаляется

В приложении я работаю, я есть родительский контейнер (List, в моем примере), который содержит список детей (Герой, в моем примере). Список управляется внешним объектом. Для простоты я объявил объект непосредственно в JS. (В моем реальном приложении хранилище данных должным образом помещено в имена и т. Д.)

Проблема, которая у меня есть, в списке у меня есть три элемента, если я удаляю элемент из середины, отображается список, который удаляет последний элемент. Однако внешний объект отражает правильный список.

Например:

  • Мой список содержит элементы: колпачок, Thor, Халка
  • Если удалить "Thor", "шапку" и "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, перечисленных в верхней части этого вопроса.

Edit:

Основываясь на комментарии от madox2, nicole, nuway и Damien Leroux, вот что я в конечном итоге делает:

https://jsfiddle.net/wbellman/ghuw2ers/10/

Я хотел бы был способ, чтобы дать каждому кредит, вы все были большой помощью.

+2

Вы должны добавить уникальные ключи в свои элементы 'Hero', а не только индексы массивов – madox2

+0

Wow. Это сработало. https://jsfiddle.net/wbellman/ghuw2ers/7/ Однако ответ nuway исправляет его, и мне не нужно рефакторировать. –

ответ

-2

Проблема с ключами.Поскольку ключ взят из индекса, этот ключ уже используется и, таким образом, показан герой с этим ключом.

изменить его key={Math.random() * 100} и он будет работать

+0

Он работает, но он заставляет повторно отображать весь компонент Hero в каждом процессе рендеринга. Это не рекомендуется вообще. Вместо этого используйте решение, данное @nicole –

+1

Я согласен. Ответ @ nicole - лучшее решение – nuway

+1

Я также согласен, но в моем фактическом приложении у моего ребенка есть законное состояние, с которым я не могу покончить. Я закончил делать хранение рандомизированного индекса на основе принципа, который вы предложили. Итак ... var heros = [{id: Math.random() * 100, name: "cap"}] ... это предотвращает повторную визуализацию, сохраняет мое поле и позволяет мне сохранять состояние моего ребенка. Хотя, если есть лучший способ, я буду за это. –

2

Изменение класса героя этого исправили проблему отображения неправильное имя героя для меня:

var Hero = React.createClass({ 
    render() { 
    return (
     <li>Hello {this.props.hero.name} | <button type="button" onClick={this.props.onRemove}>-</button></li> 
    ); 
    } 
}); 

т.е. я удалил локальное состояние из класса и использовать опору непосредственно.

Вообще-то, попробуйте использовать локальный магазин только тогда, когда вам это действительно нужно. Постарайтесь думать о своих компонентах как о безгражданстве, то есть они получают что-то через реквизит и отображают его, вот и все.

Вдоль этих строк вам следует рассмотреть возможность передачи списка героев через реквизиты в свой компонент List.

+0

Как я уже говорил выше, хотя мой пример делает глупое использование состояния, мое фактическое приложение имеет законное состояние, от которого я не могу избавиться. Что касается прохождения в списке, я согласен, я был неаккуратным на моем примере. –

+1

Моя ментальная модель в настоящее время заключается в том, что если у вас есть данные во внутреннем состоянии компонента, а также снаружи, происходит что-то странное ... Я пытаюсь использовать только один или другой, но не оба с одинаковыми данными. Рассматривали ли вы использование более сложной системы управления государственными органами, например, Redux? Возможно, это поможет вам получить более унифицированное представление о ваших данных. – Nicole

+0

Опять же, не слишком зацикливайтесь на примере. Я просто взломал что-то вместе, чтобы проиллюстрировать проблему. Он не является репрезентативным для всего приложения. Дизайн на скрипке, по общему признанию, неудобен, но это не так в приложении. Приложение «Элемент списка» содержит несколько полей, указывающих разные данные и определенное изменение поля на основе данных на этой панели. Пример: каждая панель описывает тип автомобиля для производства. Я просто не понял «ключевое» поле. –

0

, если у вас действительно есть проблемы с управления вашими данными, вы должны использовать Flux или Redux.

в этом коде:

heroList = _.filter(heroList, function(h){ return h.name !== hero.name;}); 

я просто не понимаю, почему вы FILER в heroList вместо this.state.heros? каждый раз, когда вы добавляете или удаляете героя, список героя в вашей текущей области не должен храниться в состоянии? глобальный heroList - это только начальное состояние.

+0

В реальном приложении мне нужно отслеживать исходный список, и у меня есть несколько фильтрованных контейнеров с другими полями, которые определяют конкретный отфильтрованный список для каждого. Примеры состояний и городов. Каждая новая адресная панель будет фильтровать города в соответствии с выбранным состоянием. Чтобы сделать более интересным, мне приходится загружать данные приложения на передний план, поэтому все данные о городе и состоянии приобретаются при загрузке страницы без отдельных запросов ajax. Это не идеально, но это требование для этого приложения. –

 Смежные вопросы

  • Нет связанных вопросов^_^