противоречивое значение ввода в реагировать при удалении дом - PullRequest
0 голосов
/ 21 сентября 2018

Я не могу получить это простое добавление и удаление правильных входных данных, когда у меня есть 3 поля, я заполняю все входные данные, я нажимаю удалить на 2-м элементе, я думаю, чтобы увидеть значения 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>
    );
  }
}

Демо: https://codesandbox.io/s/kwkoj33o2v

Ответы [ 4 ]

0 голосов
/ 21 сентября 2018

Очень похоже на ответ @Bernardo Siqueira, но:

  • Упрощает поля для использования поля name в качестве id
  • Показывает текущую структуру / значенияthis.state.Fields массив
  • Запрещает пользователю удалять поля, если есть только одно
  • Добавляет параметр для отправки формы

Рабочий пример: https://codesandbox.io/s/qm96vv8z9

index.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)}
      
);} render (, document.getElementById ("root"));

FieldInput.js

import map from "lodash/map";
import React from "react";

export default ({ Fields, handleChange, deleteField }) =>
  map(Fields, ({ name }, key) => (
    <div key={name} style={{ marginBottom: 20 }}>
      <input
        className="uk-input"
        onChange={handleChange(name)}
        name={name}
        placeholder="Write something..."
        type="text"
        value={Fields[key].value}
        style={{ width: 300, marginRight: 20 }}
      />
      <button
        className="uk-button uk-button-danger"
        style={{ display: "inline-block" }}
        onClick={() => deleteField(name)}
        disabled={Fields.length === 1}
      >
        <i className="fa fa-times" aria-hidden="true" />
      </button>
    </div>
  ));
0 голосов
/ 21 сентября 2018

1 ошибка наверняка заключается в том, что при установке идентификатора предметов на длину.Так что если вы добавите 2, удалите первый, а затем добавите один, у вас будет два с одинаковым идентификатором.

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

Я бы сделал добавление / удаление на основе индекса массива в этом случае вместо этогорешить.

0 голосов
/ 21 сентября 2018

Помимо значений, которые не сохраняются при изменении состояния, входам присваиваются неправильные идентификаторы, что приводит к тому, что несколько имеют одинаковые идентификаторы и удаляются вместе.Вот простое удобочитаемое исправление с методом 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, а не элемент input.Это ничего не нарушало, но хорошо следовать этому правилу.

0 голосов
/ 21 сентября 2018

Значения входов должны быть управляемыми для того, чтобы они придерживались.Если они не контролируются, значения сохранятся только до конца жизненного цикла этого ввода, и, поскольку они воссоздаются при рендеринге, если их позиция изменилась, они теряют введенное значение.

Это должно работать:

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

Редактировать: Изменено на идентификаторы, чтобы использовать uuid для гарантии уникальности, но, честно говоря, вам обычно не нужно присваивать идентификаторы массиву компонентовв состоянии, как указано в другом ответе.Вы можете обойтись без использования только индексов, или если у вас уже есть врожденный идентификатор в данных компонента, это также хорошо для использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...