Не работает setState

340
01 июля 2021, 23:10

Изучаю React.js. У меня есть форма для добавления компонентов на страницу. Я делаю валидацию этой формы. При клике на кнопку Add срабатывает функция onBtnClickHandler() которая получает значения из инпутов формы и обновляет state. В каждом инпуте у меня есть атрибут name, значение этого атрибута становится ключом, value из инпута становится значением это все у меня попадает в новый state. Форма работает хорошо. Далее c помощью функции validate() я проверяю было ли что-либо введено в инпут и обновляю state. Для этого у меня есть объект objectItems, куда я записываю состояние своего инпута, nameМоегоИнпутаIsValid : true или false. Тоже все работает. У меня в objectItems есть еще свойство formIsValid, которое по умолчанию равно false. В функции validateData() я проверяю, чтобы this.state.objectItems значение всех nameМоегоИнпутаIsValid было true и хочу обновить state переписать formIsValid : true. Но стейт не обновляется, и я не понимаю почему.

import React, { Component } from 'react';
import Card from './Card';
import apiCall from '../../Api/mockedApi';
import CardsGenerator from './CardsGenerator';

class CardsContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoaded: false,
      items: [],
      objectItems: {
        genderIsValid: false,
        priceIsValid: false,
        titleIsValid: false,
        imageUrlIsValid: false,
        formIsValid: false,
      },
    };
    this.deleteCard = this.deleteCard.bind(this);
    this.onChangeInput = this.onChangeInput.bind(this);
    this.onBtnClickHandler = this.onBtnClickHandler.bind(this);
    this.validate = this.validate.bind(this);
    this.validateData = this.validateData.bind(this);
  }
  componentDidMount() {
    apiCall().then(
      (result) => {
        this.setState({
          isLoaded: true,
          items: result,
        });
      },
      (error) => {
        this.setState({
          isLoaded: true,
          error,
        });
      },
    );
  }
  onChangeInput(event) {
    const { name } = event.currentTarget;
    const { value } = event.currentTarget;
    this.setState(state => ({ objectItems: { ...state.objectItems, [name]: value, [`${name}IsValid`]: this.validate(value) } }));
  }
  onBtnClickHandler(e) {
    e.preventDefault();
    this.setState(state => ({ items: [...state.items, state.objectItems] }));
    console.log(this.state.objectItems);
    this.validateData();
  }
  validate(value) {
    if (typeof value === 'string') {
      return value.length > 2;
    } if (typeof value === 'number') {
      return value >= 0;
    }
    return value;
  }
  validateData() {
    const {
      genderIsValid, priceIsValid, titleIsValid, imageUrlIsValid, formIsValid,
    } = this.state.objectItems;
    if (genderIsValid === true && priceIsValid === true && titleIsValid && imageUrlIsValid === true) {
      this.setState(() => ({ objectItems: { formIsValid: true } }));
      // this.setState({objectItems:{formIsValid:true}})
    }
    console.log(genderIsValid, priceIsValid, titleIsValid, imageUrlIsValid, formIsValid);
  }
  deleteCard(e, index) {
    e.preventDefault();
    const { items } = this.state;
    const newItems = items.filter((item, i) => i !== index);
    this.setState(() => ({
      items: newItems,
    }));
  }

  render() {
    const { error, isLoaded, items } = this.state;
    const itemColorBorder = () => this.state.objectItems.map(
      (item, index, arr) => (item === true ? 'green' : 'red'),
    );
    if (error) {
      return <div>No cards yet</div>;
    } if (!isLoaded) {
      return <div>Loading...</div>;
    }
    return (
      <React.Fragment>
        {items.map(
          (item, index) => <Card info={item} index={index} del={this.deleteCard} />,
        )}
        <CardsGenerator id="cardGenerateForm" key={9379992} add={this.onChangeInput} submit={this.onBtnClickHandler} borderColor={itemColorBorder} disabled={this.state.objectItems.formIsValid} validate={this.validate} />
      </React.Fragment>
    );
  }
}
export default CardsContainer;
Answer 1

Код в стиле

this.setState({value});
console.log(this.state.value);

не даст желаемого результата, потому что setState() - это асинхронная операция.

Для того чтоб выполнить какой-то код после установки состояния компонента, можно передать callback вторым параметром:

this.setState({value}, () => {
  // вот тут state уже находится в нужном состоянии
  console.log(this.state.value);
});

В случае кода из вашего примера это будет как-то так:

this.setState(state => ({ items: [...state.items, state.objectItems] }), () => {
    console.log(this.state.objectItems);
    this.validateData();
});
READ ALSO
Изучаю JavaScript, возник вопрос [закрыт]

Изучаю JavaScript, возник вопрос [закрыт]

Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском

95
Яндекс карты. Как получить равномерно распределенные точки по региону?

Яндекс карты. Как получить равномерно распределенные точки по региону?

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

101
Как выровнять по центру баннер?

Как выровнять по центру баннер?

Как сделать чтобы баннер выравнивался по центру, а не с левой стороныИспользую CMS Xenforo 2

113
Как подсветить или изменить стиль некоторых букв в строке

Как подсветить или изменить стиль некоторых букв в строке

Как сделать подобие подсветки синтаксиса?

90