Javascript 如何删除特定的子组件?

Javascript 如何删除特定的子组件?,javascript,reactjs,Javascript,Reactjs,JSFiddle: 当我从ServiceList组件中删除子ServiceItem组件时,我遇到了一个问题,列表中最后一个ServiceItem被删除,而不是目标ServiceItem。上面的JSFiddle链接将有助于理解这个问题,只需确保在输入字段中输入一些可识别的信息,以便查看删除的内容 如何修复应用程序,以便删除相应的组件 var ServiceForm = React.createClass({ render: function() { return ( <

JSFiddle:

当我从
ServiceList
组件中删除子
ServiceItem
组件时,我遇到了一个问题,列表中最后一个
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" : 'test@example.com',
        "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')
);
var ServiceForm=React.createClass({
render:function(){
返回(
{this.renderServiceItemList()}
+附加新服务项
提交
);  
},
getInitialState:函数(){
返回({
serviceItems:[此.renderServiceItem]
});
},
handleFormSubmission:功能(事件){
event.preventDefault();
var data=this.refs.service_item_list.getAllServiceItems();
var json={
“服务请求”:{
“服务”:数据,
“其他收件人”:test@example.com',
“评论”:“你好,世界!”
}
};
log(json);
},
addServiceItem:函数(事件){
var copy=this.state.serviceItems.slice();
copy.push(此.renderservice项);
这是我的国家({
服务项目:副本
});
},
renderServiceItem:函数(项,i){
返回(
);
},
removeServiceItem:函数(事件){
var索引=parseInt(event.target.value,10);
var copy=this.state.serviceItems.slice();
拷贝。拼接(索引,1);
这是我的国家({
服务项目:副本
});
},
renderServiceItemList:函数(){
返回(
);
}
});
var ServiceItemList=React.createClass({
render:function(){
var含量;
if(this.props.serviceItems.length<1){
内容=没有服务项目,请单击下面的附加新服务项目!;
}否则{
content=this.props.serviceItems.map(this.props.renderServiceItem);
}  
返回(
{content}
);
},
getAllServiceItems:函数(){
var数据=[];
for(此.refs中的变量ref){
data.push(this.refs[ref].serializeItem());
}
合并的var=[].concat.apply([],数据);
返回(合并);
}
});
var ServiceItem=React.createClass({
render:function(){
返回(
服务项目
换油
轮胎转动
新雨刮片
顾客
特洛伊
戴夫
布兰登
制造商
模型
);
},
getInitialState:函数(){
返回({
服务类型:[],
客户:'',
制造商:“”,
模型:“”
});
},
序列化项:函数(){
var customer=this.refs.customer.value;
var manufacturer=此.refs.manufacturer.value;
var模型=this.refs.model.value;
var selected=this.getSelectedServiceItems();
var services=this.getSelectedServiceItems().map(函数(项){
返回(
{
“服务”:{
“服务类型”:项目,
“客户”:客户,
“制造商”:制造商,
“模型”:模型
}      
}
)
});
返回(服务);
},
getSelectedServiceItems:函数(){
var select=this.refs.service\u类型;
var values=[].filter.call(select.options,函数(o){
返回o.selected;
}).map(功能(o){
返回o值;
});
返回(值);
}
});
ReactDOM.render(
,
document.getElementById('容器')
);

您的问题在于
键={i}

反应列表要求项目的键对于该项目是唯一的,无论该项目在列表中的位置如何。这允许react在更新时对列表进行智能管理

React不会正确呈现以下更新:

From:                         To:
name:     key:                name:          key:
Bill      0                   Bill           0
Charlie   1                   Dave           1
Dave      2
因为react认为Charlie记录是不变的(因为键是不变的)

我建议您将检索到的服务项中的某种ID作为密钥

在名字上,例如

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

在这种情况下,React将正确地呈现更新(因为密钥对于项目是唯一的)。

谢谢,我仍在尝试解决此问题,但您正确地识别了我的逻辑中的漏洞。我只需要找出如何缓解此漏洞,因为我没有使用任何唯一ID[即,这些是尚未提交到数据库的新记录]任何种类的。缓解=唯一ID,也可以是创建服务项时的时间戳。