【问题标题】:How to add json data to an array onClick?如何将json数据添加到数组onClick?
【发布时间】:2019-04-27 23:21:10
【问题描述】:

我是 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>
    );
  }
}

我希望它显示我一个接一个点击的所有设备,但现在每个点击的设备只是替换前一个点击的设备

【问题讨论】:

    标签: javascript arrays json reactjs fetch


    【解决方案1】:

    我认为你很接近。您似乎将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>
    

    希望这会有所帮助。

    【讨论】:

    • 嘿,非常感谢!当我这样做时,有没有办法将每个新添加的设备放在自己的线上?我只是问,因为最终我希望能够创建一个删除按钮,其中每个设备都有一个红色 X,用户可以单击以从列表中删除。
    • 这基本上只是在 JSX 中布局页面时的格式。你可以这样做: this.state.bag.map((device, index) =>

      {device}

      );然后您的删除函数处理程序将使用数组拼接函数删除该索引处的元素。看看这个页面:reactjs.org/docs/lists-and-keys.html
    • 另一个非常好的 React 资源:egghead.io/courses/the-beginner-s-guide-to-react ...如果你有兴趣! :)
    【解决方案2】:

    问题在于您的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>
    

    【讨论】:

    • 感谢您的回复!我注意到这两种方法都将设备添加到同一行,是否可以这样做,但每个设备都在自己的行上?我想在每个设备旁边添加一个删除按钮,以便在单击时从阵列中删除该设备。
    • @Emily 我对答案进行了编辑,以解释如何从包中取出物品。让我知道这是否有帮助!将来,您可能还会考虑将整个设备或 id 放入 bag 数组中,具体取决于您要对 bag 做什么。
    • @Emily 根据我发布的代码,我唯一能想到的是,如果您在 filter 回调函数中放置 ===== 而不是 !==。我还意识到,当我写 d.title !== deviceTitle 时,我在那个函数中犯了一个错误,它应该是 d !== deviceTitle,因为 d 已经是一个设备的标题,因为它是 state.bag 的一个元素。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    相关资源
    最近更新 更多