如何将json数据添加到数组onClick?

时间:2019-04-27 23:21:10

标签: javascript arrays json reactjs fetch

我是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 个答案:

答案 0 :(得分:2)

我认为你很近。看来您正在弄混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>

希望这会有所帮助。

答案 1 :(得分:0)

问题出在您的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),
  });
}

然后在您的render方法中,您将得到以下内容:

<ul>
  {this.state.bag.map(deviceTitle => (
    <li>
      <span>{ deviceTitle }</span>
      <button onClick={ e => this.removeDevice(e, deviceTitle) }>remove</button>
    </li>
  ))}
</ul>