Добавить объект в массив в React.js

Я знаю это простой вопрос, но сейчас я борюсь с ним. Просто я пытаюсь добавить новый объект в массив, полученный из ввода. Вот простая форма внутри рендера:

render() {
  return (
    <div className = "container">
      <form onSubmit = {this.handleSubmitTopic}>
        <input onChange = {this.handleTopicName} placeholder = "add topic name" /><br />
        <input onChange = {this.handleQ1} type = "text" placeholder = "add question" /><br />
        <input onChange = {this.handleQ2} type = "text" placeholder = "add question" /><br />
        <button>Save</button>
      </form>
    </div>
  );
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

вот функции дескриптора onChange:

handleTopicName = (e) => {
    this.setState({ topicName: e.target.value });
  }

  handleQ1 = (e) => {
    const question = e.target.value;
    const qInput = {
      answer: 'no answer',
      question,
      questionId: uuid(),
    };
    const qArray = this.state.questions.slice();
    qArray.push(qInput);
    this.setState(prevState => ({ questions: qArray }));
  }

  handleQ2 = (e) => {
    const qInput = {
      answer: 'no answer',
      question: e.target.value,
      questionId: uuid(),
    };
    const qArray = this.state.questions.slice();
    qArray.push(qInput);
    this.setState(prevState => ({ questions: qArray }));
  }

  handleSubmitTopic = (e) => {
    e.preventDefault();
    this.props.onSaveTopic({
      topicName: this.state.topicName,
      questions: this.state.questions,
    });
  }
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

и последнее, вот состояние:

state = {
  topicName: '',
  questions: [],
}

Я пробовал добавлять объекты с таким оператором распространения

this.setState({questions: [...this.state.questions, {here goes question object}]})

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

вот скриншот результатов:

Добавить объект в массив в React.js

Как я могу решить эту проблему?

Вы добавляете объект в массив при изменении ввода. Вы действительно этого хотите?

Tholle 30.07.2018 16:07

Я просто хочу добавить новый объект при сохранении формы

anarzone 30.07.2018 16:13

@anarzone просто используйте событие onBlur при вводе вместо onChange. <input onBlur = {this.handleTopicName} placeholder = "добавить название темы" />

Javed Shaikh 30.07.2018 16:19
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
3
115
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Используйте событие onBlur вместо onChange. OnBlur срабатывает, когда фокус выходит за пределы элемента ввода. Событие onChange возникает, когда значение элемента было изменено.

render() {
  return (
    <div className = "container">
      <form onSubmit = {this.handleSubmitTopic}>
        <input onBlur = {this.handleTopicName} placeholder = "add topic name" /><br />
        <input onBlur = {this.handleQ1} type = "text" placeholder = "add question" /><br />
        <input onBlur = {this.handleQ2} type = "text" placeholder = "add question" /><br />
        <button>Save</button>
      </form>
    </div>
  );
}

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

anarzone 30.07.2018 16:52
Ответ принят как подходящий

Вот другой ответ, но это кардинально меняет логику вашего кода.

class App extends React.Component {
  state = {
    topicName: '',
    inputs: {},
    questions: [],
  }

  handleTopicName = e =>
    this.setState({ topicName: e.target.value });


  handleInputs = (e) => {
    const { name, value } = e.target
    this.setState(prevState => ({ inputs: { ...prevState.inputs, [name]: value } }));
  }

  handleSubmitTopic = (e) => {
    e.preventDefault();
    const {inputs} = this.state;
    const questions = Object.keys(inputs).map( key => (
      {
        answer: 'no answer',
        question: inputs[key],
      //questionId: uuid(),
      }
    ));
    
    this.setState({ questions });

    /* this.setState( { questions }, () => 
      this.props.onSaveTopic( {
        topicName: this.state.topicName,
        questions,
      } )
     );*/
  }

  render() {
    console.info( this.state );
    return (
    <div className = "container">
      <form onSubmit = {this.handleSubmitTopic}>
        <input onChange = {this.handleTopicName} placeholder = "add topic name" /><br />
        <input name = "q1" onChange = {this.handleInputs} type = "text" placeholder = "add question" /><br />
        <input name = "q2" onChange = {this.handleInputs} type = "text" placeholder = "add question" /><br />
        <button>Save</button>
      </form>
    </div>
  );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id = "root"></div>

Я создал одну функцию для обработки входных данных: handleInputs. Эта функция обрабатывает оба входа с их атрибутом name. Итак, мы используем эти входы для создания questions. Это делается в функции handleSubmitTopic.

Здесь, используя объект inputs, мы отображаем его в новый массив questions. В рабочем коде я просто установил состояние questions. Благодаря этому фрагмент работает. Если вы закомментируете это и воспользуетесь своей версией, вы можете использовать onSaveTopic. Здесь, после установки состояния questions, в функции обратного вызова setState мы делаем это, поскольку setState является асинхронным.

Кроме того, есть метод console.info в render, чтобы увидеть, что здесь происходит.

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

devserkan 30.07.2018 18:11

Другие вопросы по теме