删除dom时反应中的输入值不一致

时间:2018-09-21 03:39:50

标签: javascript reactjs ecmascript-6

我无法正确实现这种简单的添加和删除输入,当我有3个字段时,我填写了所有输入,单击了第二项上的Delete,我想看到的是值1和2,但是没有?

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rows: [
        {
          id: 1
        }
      ]
    };
  }
  addRow = () => {
    this.setState(
      {
        rows: [...this.state.rows, { id: this.state.rows.length + 1 }]
      },
      () => console.log(this.state.rows)
    );
  };

  deleteRow = id => {
    console.log(id);
    const { rows } = this.state;
    this.setState({
      rows: rows.filter(row => row.id !== id)
    });
  };

  render() {
    const { rows } = this.state;
    return (
      <div>
        {rows.map(o => (
          <div>
            <input key={o.id} id={o.id} placeholder={"text"} type="text" />
            <div
              style={{ display: "inline-block" }}
              onClick={e => this.deleteRow(o.id)}
            >
              x
            </div>
          </div>
        ))}
        <button onClick={this.addRow}>add</button>
      </div>
    );
  }
}

演示:image

4 个答案:

答案 0 :(得分:0)

需要对输入的值进行控制,以使其保持不变。如果不加以控制,则值将一直保留到该输入生命周期的尽头,并且由于更改了位置而在渲染中重新创建了它们,因此它们会丢失键入的值。

这应该有效:

import React from "react";
import ReactDOM from "react-dom";
import uuid from "uuid";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentId: 1,
      rows: [
        {
          id: uuid(),
          value: '',
        }
      ]
    };
  }
  addRow = () => {
    this.setState(
      {
        rows: [...this.state.rows, { id: uuid(), value: '' }]
      },
      () => console.log(this.state.rows)
    );
  };

  deleteRow = id => {
    console.log(id);
    const { rows } = this.state;
    this.setState({
      rows: rows.filter(row => row.id !== id)
    });
  };

  handleChangeRow = (id) => ({target: {value}}) => this.setState({rows: this.state.rows.map(row => row.id === id ? {...row, value} : row)})

  render() {
    const { rows } = this.state;
    return (
      <div>
        {rows.map(o => (
          <div>
            <input value={o.value} key={o.id} id={o.id} placeholder={"text"} type="text" 
onChange={this.handleChangeRow(o.id)}/>
            <div
              style={{ display: "inline-block" }}
              onClick={e => this.deleteRow(o.id)}
            >
              x
            </div>
          </div>
        ))}
        <button onClick={this.addRow}>add</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

https://codesandbox.io/s/p785wv1z7m

编辑:更改为ID以使用uuid来保证唯一性,但是为了公平起见,您通常不需要为状态中的组件数组分配ID,如另一个答案所述。您可以只使用索引,或者如果组件数据中已经具有固有ID,那也可以使用。

答案 1 :(得分:0)

确定有1个错误是在您将项目ID设置为长度时。因此,如果您添加2,请删除第一个,然后添加一个,您将拥有两个具有相同ID的

[{id: 1}]
// Push one
[{id: 1}, {id: 2}]
// Delete value of 1
[{id: 2}]
// Push one
[{id: 2}, {id: 2}] // wooops!

在这种情况下,我会根据数组的索引进行添加/删除,以解决问题。

答案 2 :(得分:0)

除了在状态更改中未保存值外,还为输入分配了不正确的ID,这导致多个ID具有相同的ID并被一起删除。这是一个简单易读的修复程序,它带有saveValue方法,用于在每次更改时保存输入值:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentId: 1,
      rows: [
        {
          id: 1,
          value: ''
        }
      ]
    };
  }

  addRow = () => {
    this.setState(
      {
        currentId: this.state.currentId + 1,
        rows: [...this.state.rows, { id: this.state.currentId + 1, value: '' }]
      },
      console.log(this.state.rows)
    );
  };

  deleteRow = id => {
    console.log(id);
    let rows = this.state.rows;
    this.setState({
      rows: rows.filter(row => row.id !== id)
    });
  };

  saveValue = (e, id) => {
    let rows = this.state.rows;
    rows[id - 1].value = e.target.value;
    this.setState({ rows: rows });
  }

  render() {
    const { rows } = this.state;
    return (
      <div>
        {rows.map(o => (
          <div key={o.id}>
            <input id={o.id} value={o.value} placeholder={"text"} type="text" onChange={e => this.saveValue(e, o.id)}/>
            <div
              style={{ display: "inline-block" }}
              onClick={() => this.deleteRow(o.id)}
            >
              x
            </div>
          </div>
        ))}
        <button onClick={this.addRow}>add</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

https://codesandbox.io/s/qqvvq27k36

还要注意,当您使用map添加元素时,map中最顶层的元素(在这种情况下为div)需要具有key属性,而不是输入元素。那并没有破坏任何东西,但是遵循该规则是一种很好的做法。

答案 3 :(得分:0)

与@Bernardo Siqueira的答案非常相似,但是:

  • 简化字段以将字段y1用作name
  • 显示id数组的当前结构/值
  • 如果只有一个字段,则防止用户删除字段
  • 添加了提交表单的选项

工作示例:https://codesandbox.io/s/qm96vv8z9

index.js

this.state.Fields

FieldInput.js

import map from "lodash/map";
import filter from "lodash/filter";
import React, { Component } from "react";
import { render } from "react-dom";
import FieldInput from "./FieldInput";
import "uikit/dist/css/uikit.min.css";
import "./styles.css";

class App extends Component {
  state = {
    fieldsCount: 1,
    Fields: [
      {
        name: "Field0",
        value: ""
      }
    ]
  };

  handleChange = name => ({ target: { value } }) => {
    this.setState(prevState => ({
      Fields: map(
        this.state.Fields,
        field => (field.name === name ? { ...field, value } : field)
      )
    }));
  };

  showFieldValues = fields => {
    return map(fields, ({ value }) => value);
  };

  handleSubmit = e => {
    e.preventDefault();

    alert(`Field value(s): ${this.showFieldValues(this.state.Fields)}`);
  };

  addField = () => {
    this.setState(prevState => ({
      Fields: [
        ...this.state.Fields,
        {
          name: `Field${this.state.fieldsCount}`,
          value: ""
        }
      ],
      fieldsCount: this.state.fieldsCount + 1
    }));
  };

  deleteField = name => {
    this.setState(prevState => ({
      Fields: filter(this.state.Fields, field => field.name !== name)
    }));
  };

  render = () => (
    <form onSubmit={this.handleSubmit} style={{ textAlign: "center" }}>
      <h1>Dynamic Field Creation</h1>
      <FieldInput
        {...this.state}
        deleteField={this.deleteField}
        handleChange={this.handleChange}
      />
      <button
        type="button"
        style={{ marginRight: 20 }}
        className="uk-button uk-button-primary"
        onClick={this.addField}
      >
        Add Field
      </button>
      <button type="submit" className="uk-button uk-button-secondary">
        Submit
      </button>
      <pre style={{ textAlign: "left", height: 300, scrollY: "auto" }}>
        <code>{JSON.stringify(this.state.Fields, null, 4)}</code>
      </pre>
    </form>
  );
}

render(<App />, document.getElementById("root"));