Как добавить данные json в массив onClick? - PullRequest
0 голосов
/ 28 апреля 2019

Я новичок в React / использую данные API json в проекте, поэтому у меня возникли небольшие проблемы. Я создал функцию, в которой пользователь может ввести поисковый запрос, и отобразится список устройств, связанных с его запросом. Эти имена устройств извлекаются из API. Я пытаюсь сделать так, чтобы при нажатии знака «плюс» рядом с устройством это устройство добавлялось в новый массив, который затем отображался на экране.

Я не на 100% знаком с концепцией состояния в React, и я думаю, что именно в этом моя проблема (в функции addDevice). Это частично работает, когда я щелкаю устройство и оно отображается внизу, но когда я щелкаю другое устройство, вместо добавления в список, оно просто заменяет первое устройство.

class App extends React.Component {
  state = {
    search: "",
    devices: [],
    bag: []
  };

  addDevice = (e, data) => {
    console.log(data);
    const newData = [this.state.devices.title];
    this.setState({
      bag: newData.concat(data)
    });
  };

  onChange = e => {
    const { value } = e.target;
    this.setState({
      search: value
    });

    this.search(value);
  };

  search = search => {
    const url = `https://www.ifixit.com/api/2.0/suggest/${search}?doctypes=device`;

    fetch(url)
      .then(results => results.json())
      .then(data => {
        this.setState({ devices: data.results });
      });
  };

  componentDidMount() {
    this.search("");
  }

  render() {
    return (
      <div>
        <form>
          <input
            type="text"
            placeholder="Search for devices..."
            onChange={this.onChange}
          />
          {this.state.devices.map(device => (
            <ul key={device.title}>
              <p>
                {device.title}{" "}
                <i
                  className="fas fa-plus"
                  style={{ cursor: "pointer", color: "green" }}
                  onClick={e => this.addDevice(e, device.title)}
                />
              </p>
            </ul>
          ))}
        </form>
        <p>{this.state.bag}</p>
      </div>
    );
  }
}

Я хочу, чтобы он отображал все устройства, которые я нажимал одно за другим, но сейчас каждое нажатие устройства просто заменяет предыдущее нажатие

Ответы [ 2 ]

2 голосов
/ 28 апреля 2019

Я думаю, что вы близко.Похоже, что вы смешиваете массив devices и массив bag.

Я бы предложил использовать Array.from для создания копии вашего массива состояний.Затем вставьте новый элемент в массив.Concat используется для объединения двух массивов.

addDevice = (e, data) => {
  // create new copy of array from state
  const newArray = Array.from(this.state.bag);

  // push new item into array
  newArray.push(data);

  // update the state with the new array
  this.setState({
    bag: newArray
  });
}

Тогда, если вы хотите отобразить названия устройств в виде строки, разделенной запятыми, вы можете просто сделать:

<p>{this.state.bag.join(', ')}</p>

Надеюсь, это поможет.

0 голосов
/ 28 апреля 2019

Проблема связана с вашим addDevice методом, а именно с тем, как вы создаете newData.Вы устанавливаете newData в [this.state.devices.title], что оценивается в [undefined], поскольку this.state.devices является массивом и, следовательно, не имеет атрибута с именем title.Таким образом, обновленное значение state.bag будет [undefined, data] и будет отображаться только как data, которое является названием самого последнего нажатого устройства.

Я думаю, что вы хотите сделать здесь - добавитьназвание кликаемого устройства в массиве state.bag.Вы можете сделать это с помощью метода addDevice, подобного следующему:

addDevice = (e, data) => {
  console.log(data);
  const newBag = this.state.bag.concat(data);
  this.setState({
    bag: newBag
  });
};

Хотя лучший способ обновления state.bag будет использовать функциональную форму setState и оператор распространения (...) более распространено для такого рода вещей, чем использование concat.Также было бы полезно переименовать data во что-то более понятное (например, deviceTitle).Пример:

addDevice = (e, deviceTitle) => {
  this.setState(prevState => ({
    bag: [...prevState.bag, deviceTitle],
  });
}

Редактировать:

Если вы хотите добавить функциональность для удаления устройств из state.bag, вы можете создать метод с именем removeDevice и добавитькнопка рядом с каждым элементом сумки при рендеринге.

Например:

removeDevice = (e, deviceTitle) => {
  this.setState(prevState => ({
    bag: prevState.bag.filter(d => d !== deviceTitle),
  });
}

Тогда в вашем методе рендеринга вы получите что-то вроде этого:

<ul>
  {this.state.bag.map(deviceTitle => (
    <li>
      <span>{ deviceTitle }</span>
      <button onClick={ e => this.removeDevice(e, deviceTitle) }>remove</button>
    </li>
  ))}
</ul>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...