Проблема с обновлением объекта в состоянии значениями из четырех разных тегов выбора

#reactjs #state

#reactjs #состояние

Вопрос:

Итак, у меня есть страница дизайна продукта, на которой пользователь будет выбирать параметры из 4 разных полей выбора, а затем из них будет отображаться изображение продукта. Итак, я собираюсь обновить изображение на основе объекта в состоянии с каждым параметром внутри него, но у меня возникли проблемы с обновлением состояния.

Изначально у меня был один handlechange, который обновил все значения в объекте, затем попробовал несколько функций handlechange, как показано ниже, и попытался распространить значение каждого параметра, но это тоже не работает, вот компонент на данный момент ниже. В настоящее время он обновляет состояние, но удаляет другие элементы в объекте после выбора выпадающего списка. Я предполагаю, что это исправлено с помощью prevstate каким-то образом, но не уверен.

 
import React, { Component } from 'react';
import Swal from 'sweetalert2'
import placeholder from '../../imgs/CPC Yellow Cube Planter.jpg'



class Design extends Component {

  constructor() {
    super()
    this.state= 
    {
      value: { 
        plantstyle: "",
        size: "",
        colour: "",
        finish: ""
    }
    }

    this.handleChange = this.handleChange.bind(this);
    this.handleChange2 = this.handleChange2.bind(this);
    this.handleChange3 = this.handleChange3.bind(this);
    this.handleChange4 = this.handleChange4.bind(this);

  }


  handleChange(event) {
      this.setState({
        value: {
                  plantstyle: event.target.value,
               }
      })
  }

  handleChange2(event) {
    this.setState({
      value: {
                size: event.target.value,
             }
    })
}

handleChange3(event) {
  this.setState({
    value: {
              colour: event.target.value,
           }
  })
}

handleChange4(event) {
  this.setState({
    value: {
              finish: event.target.value,
           }
  })
}



  sweetalertFunc() {
    Swal.fire(
      'Design a planter!',
      'Personalise you product with the dropdown menus below.',
      'info'
    )
  }

  render() {

    return (
        <div className="container-fluid">

          <h1>
            Design A Planter
       </h1>


          <div className="destext">
            <p>
              Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
            </p>
          </div>

          <div className="start"><button className="astext" onClick={this.sweetalertFunc}>How does it work? </button></div>

        <form>
          <div className="select">
                <select name="plantstyledd" onChange={(e) => this.handleChange(e)}>
                        <option value="">Style</option>
                        <option value="Pillar">Pillar</option>
                        <option value="Vase">Vase</option>
                        <option value="Column">Column</option>
                        <option value="Cube">Cube</option>

                </select> 

                <select name="size" onChange={(e) => this.handleChange2(e)}>
                        <option size="">Size</option>
                        <option size="small">Small</option>
                        <option size="medium">Medium</option>
                        <option size="large">Large</option>
                </select> 

                <select name="Colour" onChange={(e) => this.handleChange3(e)}>
                    <option value="">Select colour</option>
                    <option value="red">Red</option>
                    <option value="brown">Brown</option>
                    <option value="blue">Blue</option>
                </select>

                <select name="Paint Finish" onChange={(e) => this.handleChange4(e)}>
                        <option value="">Finish</option>
                        <option value="Wood">Matt</option>
                        <option value="Wood">Paint</option>
                </select> 

            </div>

            <div className="desimg">
              <img src={placeholder} alt="placeholder"></img>

            </div>
            </form>
        </div>

    );
  }
}

export default Design

  

Ответ №1:

Я бы реструктурировал его следующим образом:

 class Design extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {
        plantstyle: "",
        size: "",
        colour: "",
        finish: "",
      },
    };
  }

  handleChange = field => event =>
    this.setState(prevState => ({
      value: {
        ...prevState.value,
        [field]: event.target.value,
      },
    }));

  sweetalertFunc() {
    Swal.fire("Design a planter!", "Personalise you product with the dropdown menus below.", "info");
  }

  render() {
    return (
      <div className="container-fluid">
        <h1>Design A Planter</h1>

        <div className="destext">
          <p>
            Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the
            industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and
            scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into
            electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of
            Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like
            Aldus PageMaker including versions of Lorem Ipsum.
          </p>
        </div>

        <div className="start">
          <button className="astext" onClick={this.sweetalertFunc}>
            How does it work?{" "}
          </button>
        </div>

        <form>
          <div className="select">
            <select name="plantstyle" value={this.state.value.plantstyle} onChange={this.handleChange("plantstyled")}>
              <option value="">Style</option>
              <option value="Pillar">Pillar</option>
              <option value="Vase">Vase</option>
              <option value="Column">Column</option>
              <option value="Cube">Cube</option>
            </select>

            <select name="size" value={this.state.value.size} onChange={this.handleChange("size")}>
              <option size="">Size</option>
              <option size="small">Small</option>
              <option size="medium">Medium</option>
              <option size="large">Large</option>
            </select>

            <select name="colour" value={this.state.value.colour} onChange={this.handleChange("colour")}>
              <option value="">Select colour</option>
              <option value="red">Red</option>
              <option value="brown">Brown</option>
              <option value="blue">Blue</option>
            </select>

            <select name="finish" value={this.state.value.finish} onChange={this.handleChange("finish")}>
              <option value="">Finish</option>
              <option value="Wood">Matt</option>
              <option value="Wood">Paint</option>
            </select>
          </div>

          <div className="desimg">
            <img src={placeholder} alt="placeholder" />
          </div>
        </form>
      </div>
    );
  }
}

export default Design;
  

Возможно, в качестве самого простого рефакторинга будет введена только функция «handleChange», потому что через curry вы передаете ключ объекта для изменения его значения, поэтому вы не повторяете код 4 раза, сохраняя остальную часть объекта как есть.

Надеюсь, я вам помог 🙂

Комментарии:

1. Вы могли бы просто использовать атрибут ‘name’ вместо отправки атрибута field для установки состояния.

2. Привет, я ответил на комментарий выше с ошибкой, которую я получаю в браузере, и ваша выдает ту же ошибку TypeError: event.target равно null

3. @matthewg не могли бы вы загрузить все файлы в изолированный проект? Потому что с приведенным выше кодом это должно работать, спасибо!

4. Редактировать: исправлено, должно было иметь event.target.value в переменной перед setstate(), спасибо за помощь

5. @matthewg это здорово, я рад! (вы должны отметить проверку, помогли ли мы вам в обоих решениях решить вашу проблему) 🙂

Ответ №2:

Вам необходимо сохранить предыдущие значения в таком состоянии —

 handleChange(event) {
  this.setState(prevState => ({
     value: {
        ...prevState.value,
        plantstyle: event.target.value,
     }
  }))
}
  

Комментарии:

1. Когда я реализую это при загрузке страницы в браузере, я получаю сообщение об ошибке «TypeError: event.target равно null» в функции setstate, вы знаете, почему это так?