2015-02-15 2 views
1

У меня возникают проблемы с удалением элементов состояния в массиве React. В следующем примере, если нажать 'тумблер' на втором элементе ('B'), вы увидите:Удаление элемента Stateful из массива ReactJS

запись Идентификатор: 0 Имя: A активен Переключить Удалить

запись ID: 1 название: B не активен Переключить Удалить

запись идентификатор: 2 имя: C активен Переключить Удалить

Если теперь нажать кнопку 'Удалить' на первом элементе ('A'):

записи ID: 0 Имя: B активно Переключить Удалить

записи Идентификатор: 1 Имя: C не активно Переключить Удалить

B изменился, но все, что я хотел сделать, это удалить и не влияют на какие-либо другие элементы. У меня есть key в соответствии с документами, и я попытался использовать ключ с префиксом строки, но это не помогло.

Есть ли способ сделать это, не нажимая состояние до TestContainer? (В моей реальной ситуации у меня много разрозненных элементов с разными типами состояний).

<div id="test"></div> 

<script type="text/jsx"> 

    var TestLine = React.createClass({ 
     getInitialState: function() { 
      return {active: true}; 
     }, 
     handleLineRemove: function(e) { 
     this.props.processLineRemove(this.props.id); 
     }, 
     toggleActive: function(e) { 
     this.setState({active: !this.state.active}; 
     }, 
     render: function() { 
     return (
      <p> 
      Entry id: {this.props.id} name: {this.props.name} 
      {this.state.active ? " Is Active " : " Is Not Active " } 
      <a onClick={this.toggleActive}>Toggle</a> 
      &nbsp;<a onClick={this.handleLineRemove}>Remove</a> 
      </p> 
     ); 
     } 
    }); 

    var TestContainer = React.createClass({ 
     getInitialState: function() { 
      return {data: {lines: ['A','B','C']}}; 
     }, 
     processLineRemove: function(index) { 
       var new_lines = this.state.data.lines.slice(0); 
       new_lines.splice(index,1); 
       var newState = React.addons.update(this.state.data, { 
       lines: {$set: new_lines} 
       }); 
      this.setState({data: newState}); 
     }, 
     render: function() { 
      var body =[]; 
      for (var i = 0; i < this.state.data.lines.length; i++) { 
       body.push(<TestLine 
          key={i} 
          id={i} 
          name={this.state.data.lines[i]} 
          processLineRemove={this.processLineRemove} />) 
      } 
      return (
       <div>{body}</div> 
      ); 
     } 
    }); 

React.render(<TestContainer />, document.getElementById('test')); 
</script> 
+0

Там всегда должны быть некоторые централизованное местоположение, которое необходимо будет уведомлен об удалении. Вы можете использовать action/dispatcher, чтобы уведомить об этом изменении и распространить его обратно, но концептуально он не сильно отличается от вашей существующей реализации, как показано. Вам нужно будет уведомить какой-либо компонент или магазин, которому принадлежат данные. – WiredPrairie

+0

Элементы успешно удаляются с помощью TestContainer, которому принадлежит массив. Однако оставшиеся элементы массива не будут повторно отображены правильно; только метки имен перемещаются, а частное состояние в TestLine не переводится в новую позицию в массиве. –

+0

Теперь вы задаете два вопроса: как управлять состоянием без привлечения «TestContainer» и как правильно отображать его. Похоже, ответ должен помочь вам. – WiredPrairie

ответ

0

Если у вас есть список предметов, и вы знаете, что элементы будут редактироваться случайным образом, я бы не создал такие ключи. Я предпочел бы создавать ключи, которые уникальны и will not overlap с другими ключами при смене списка. Достаточно простого генератора случайных ключей, такого как this.

Почему? Давайте рассмотрим каждый шаг.

Первые делают выглядит как этот

идентификатор записи: 0 Имя: A активно Переключить Удалить

записи Идентификатор: 1 имя: B не активно Переключить Удалить

записи ID: 2 название: C активен Переключить Удалить

И второй выглядит так

записи Идентификатор: 0 Имя: B не активно Переключить Удалить

записи Идентификатор: 1 имя: C активно Переключить Удалить

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

Он смотрит на первый элемент и понимает, что для «активного» флага установлено значение true на основе ключа. Таким образом, он применит то же самое к ключу 0, который находит во втором рендере. Так и далее и т. Д. Для остальных элементов.

Таким образом, если ваши ключи не перекрываются при изменении, вы можете избежать этой проблемы. Это единственный способ AFAIK. Надеюсь это поможет.

Ниже приведено описание DEMO.

Courtesy

+0

UUID решает проблему многих серверов, создавая до миллиардов uuids в секунду с почти 0% вероятностью конфликта. Здесь немного переборщить. – FakeRainBrigand

+0

полностью согласен! – Dhiraj

+0

@FakeRainBrigand будет https://lodash.com/docs#uniqueId иметь больше смысла, например (с префиксом?) – phtrivier

1

Если у вас есть список с произвольными удалений/вставок, вы не можете использовать индекс в качестве ключа. В этом случае вы можете использовать фактическое значение, потому что оно не изменяется.

var body = this.state.data.map(function(x, i){ 
    return <TestLine 
     key={x} 
     name={x} 
     processLineRemove={this.processLineRemove.bind(null, i)} /> 
}.bind(this)); 

В более сложном случае, вам нужен массив объектов, и присвоить свойство с уникальным значением каждого. Предполагая, что состояние является [makeItem('A'), makeItem('B'), ...]:

function unique(){ return ++unique.i }; 
unique.i = 0; 

function makeItem(text){ return {text: text, id: unique()}; }; 

var body = this.state.data.map(function(x, i){ 
    return <TestLine 
     key={x.id} 
     name={x.text} 
     processLineRemove={this.processLineRemove.bind(null, i)} /> 
}.bind(this));