2016-02-29 3 views
0

JSFiddle: https://jsfiddle.net/morahood/cp569zg6/38/Как удалить определенные дочерние компоненты React?

При удалении компонента ребенок ServiceItem из ServiceList компонента, я бегу на вопрос, где в списке последний ServiceItem удаляется вместо целевого ServiceItem. Вышеупомянутая ссылка JSFiddle поможет понять проблему, просто убедитесь, что вы вводите какую-то идентифицируемую информацию в поля ввода, чтобы вы могли видеть, что удаляется.

Как исправить мое приложение так, чтобы соответствующий компонент был удален?

var ServiceForm = React.createClass({ 
    render: function() { 
    return (
     <form onSubmit={ this.handleFormSubmission } > 
     { this.renderServiceItemList() } 
     <div className="btn btn-default btn-sm" onClick={ this.addServiceItem }>+ Append New Service Item</div> 
     <button type="submit" className="btn btn-success btn-lg pull-right">Submit</button> 
     </form> 
    ); 
    }, 

    getInitialState: function() { 
    return ({ 
     serviceItems: [this.renderServiceItem] 
    }); 
    }, 

    handleFormSubmission: function(event) { 
    event.preventDefault(); 
    var data = this.refs.service_item_list.getAllServiceItems(); 
    var json = { 
     "service_request" : { 
     "services" : data, 
     "additional_recipients" : '[email protected]', 
     "comments" : 'Hello world!' 
     } 
    }; 
    console.log(json); 
    }, 


    addServiceItem: function(event) { 
    var copy = this.state.serviceItems.slice(); 
    copy.push(this.renderServiceItem); 

    this.setState({ 
     serviceItems: copy 
    }); 
    }, 

    renderServiceItem: function(item, i) { 
    return (
     <ServiceItem removeServiceItem={ this.removeServiceItem } data={item} key={i} ref={"service_item_" + i} /> 
    ); 
    }, 

    removeServiceItem: function(event) { 
    var index = parseInt(event.target.value, 10); 
    var copy = this.state.serviceItems.slice(); 
    copy.splice(index, 1); 

    this.setState({ 
     serviceItems: copy 
    }); 
    }, 

    renderServiceItemList: function() { 
    return (
     <ServiceItemList serviceItems={ this.state.serviceItems } 
        renderServiceItem={ this.renderServiceItem } 
        removeServiceItem={ this.removeServiceItem } 
           ref="service_item_list" /> 
    ); 
    } 
}); 





var ServiceItemList = React.createClass({ 
    render: function() { 
    var content; 
    if (this.props.serviceItems.length < 1) { 
     content = <div className="empty-service-list">There are no service items, click on append new service item below!</div>; 
    } else { 
     content = this.props.serviceItems.map(this.props.renderServiceItem); 
    } 


    return (
     <div> 
     { content } 
     </div> 
    ); 
    }, 

    getAllServiceItems: function() { 
    var data = []; 

    for (var ref in this.refs) { 
     data.push(this.refs[ref].serializeItem()); 
    } 

    var merged = [].concat.apply([], data); 
    return(merged); 
    } 
}); 





var ServiceItem = React.createClass({ 
    render: function() { 
    return (
     <div className="row"> 
     <div className="col-sm-3"> 
      <div className="form-group service-item"> 

      <label>Service Item </label> 
      <select multiple ref="service_types" className="form-control"> 
       <option>Oil Change</option> 
       <option>Tire Rotation</option> 
       <option>New Wiper Blades</option> 
      </select> 
      </div> 
     </div> 

     <div className="col-sm-3"> 
      <div className="form-group"> 
      <label>Customer </label> 
      <select ref="customer" className="form-control"> 
       <option>Troy</option> 
       <option>Dave</option> 
       <option>Brandon</option> 
      </select> 
      </div> 
     </div>   

     <div className="col-sm-3"> 
      <div className="form-group"> 
      <label>Manufacturer </label> 
      <div className="input-group"> 
       <input ref="manufacturer" type="text" className="form-control" /> 
      </div> 
      </div> 
     </div> 


     <div className="col-sm-3"> 
      <div className="form-group"> 
      <label>Model </label> 
      <div className="input-group"> 
       <input ref="model" type="text" className="form-control" /> 
      </div> 
      <a href="#" onClick={ this.props.removeServiceItem }> 
       <span aria-hidden="true" className="remove-fields" onClick={ this.props.removeServiceItem }>&times;</span> 
      </a> 
      </div> 
     </div> 
     </div> 
    ); 
    }, 

    getInitialState: function() { 
    return({ 
     service_types: [], 
     customer: '', 
     manufacturer: '', 
     model: '' 
    }); 
    }, 

    serializeItem: function() { 
    var customer = this.refs.customer.value; 
    var manufacturer = this.refs.manufacturer.value; 
    var model = this.refs.model.value; 

    var selected = this.getSelectedServiceItems(); 

    var services = this.getSelectedServiceItems().map(function(item) { 
     return (
      { 
      "service" : { 
       "service_type" : item, 
       "customer" : customer, 
       "manufacturer" : manufacturer, 
       "model" : model 
      }  
      } 
     ) 
     }); 
    return(services); 
    }, 

    getSelectedServiceItems: function() { 
     var select = this.refs.service_types; 
     var values = [].filter.call(select.options, function (o) { 
     return o.selected; 
    }).map(function (o) { 
     return o.value; 
    }); 
    return(values); 
    } 
}); 





ReactDOM.render(
    <ServiceForm />, 
    document.getElementById('container') 
); 

ответ

2

Ваша проблема с вашим key={i}.

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

Реагировать НЕ будет оказывать следующее обновление правильно:

From:       To: 
name:  key:    name:   key: 
Bill  0     Bill   0 
Charlie 1     Dave   1 
Dave  2 

Поскольку реагировать думает, что запись Чарли остается неизменным (потому что ключ не изменяется).

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

По названию, например.

From:       To: 
name:  key:    name:   key: 
Bill  Bill    Bill   Bill 
Charlie Charlie    Dave   Dave 
Dave  Dave 

Реакция будет корректно отображать обновление в этом случае (поскольку ключ уникален для элемента).

+0

Спасибо, я все еще пытаюсь решить проблему, но вы правильно определяете пробел в своей логике. Мне просто нужно выяснить, как смягчить ее, поскольку я не начинаю с каких-либо уникальных идентификаторов (т. это новые записи, которые еще должны быть привязаны к базе данных] любого типа. – pyRabbit

+0

Смягчение = уникальные идентификаторы, которые также могут быть временными метками при создании сервисного элемента. – wintvelt