【问题标题】:Make changes to API fetch onClick in React在 React 中更改 API fetch onClick
【发布时间】:2019-10-31 02:46:28
【问题描述】:

我正在设计一个 UI 原型并从 React 中这样的 API 获取数据:

  componentWillUpdate() {
    fetch(this.state.api + this.state.query  +".json" + this.state.key)
      .then(response => {
        if (response.ok) {
          return response.json();
        } else {
          throw new Error('Oops')
        }
      })
      .then(data => this.setState({ results: data.results, isLoading: false}))
      .catch(error => this.setState({ error, isLoading: false }))
  }

我想让用户访问其他可能的类别列表。给定这样的链接:

<li data-facet="arts" onClick={this.handleCategory}>Arts</li>

还有一个像这样的处理方法:

handleCategory(event) {
    this.setState({
      query: event.target.getAttribute('data-facet')
    })
  }

如何让 UI 更新和显示新类别的数据?这几天我一直在努力解决这个问题。我已经编写了几种成功更新获取字符串的方法,但没有一种方法会强制组件重新渲染并显示新项目。谢谢。


更新完整的组件代码:

import React, { Component } from 'react'
import Moment from 'moment'
import MaterialIcon from 'material-icons-react'
import '../assets/styles/app.scss'

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoading: false,
      isMenuOpen: false,
      results: [],
      api: "the//api//here",
      query: "",
      key: "?api-key=XXXXXX"
    };

    this.handleMenu = this.handleMenu.bind(this)
    this.handleCategory = this.handleCategory.bind(this)
  }

  handleMenu() {
    this.setState({
      isMenuOpen: !state.isMenuOpen
    })
  }

  handleCategory(event) {
    this.setState({
      query: event.target.getAttribute('data-facet')
    })
  }

  componentDidMount() {
    fetch(this.state.api + this.state.query  +".json" + this.state.key)
      .then(response => {
        if (response.ok) {
          return response.json();
        } else {
          throw new Error('Oops')
        }
      })
      .then(data => this.setState({ results: data.results, isLoading: false}))
      .catch(error => this.setState({ error, isLoading: false }))
  }

  render() {
    const { results, isLoading, error } = this.state

    if (error) {
      return <div className="cards">{error.message}</div>
    }

    if (isLoading) {
      return <div className="cards">Loading...</div>;
    }

    return (
      <div className="wrapper">

        <div className="menu-trigger"><MaterialIcon icon="menu"/></div>
        <div className="menu">
          <ul>
            <li data-facet="arts" onClick={this.handleCategory}>Arts</li>
            <li data-facet="automobiles" onClick={this.handleCategory}>Automobiles</li>
            <li data-facet="books" onClick={this.handleCategory}>Books</li>
            <li data-facet="business" onClick={this.handleCategory}>Business</li>
            <li data-facet="fashion" onClick={this.handleCategory}>Fashion</li>
            <li data-facet="food" onClick={this.handleCategory}>Food</li>
            <li data-facet="health" onClick={this.handleCategory}>Health</li>
            <li data-facet="home" onClick={this.handleCategory}>Home</li>
          </ul>
        </div>

        <div className="cards">
          {results.slice(0, 10).map(result => (
            <div className="cards__card" key={result.title}>
              <a href={result.url} target="_blank"><h5>{result.title}</h5></a>
              <p>{result.abstract}</p>
              <p className="small">Published {Moment(result.published_date).format('MMMM Do YYYY, h:mm a')}</p>
            </div>
          ))}
        </div>
      </div>
    );
  }

}

export default App

【问题讨论】:

  • 你能告诉我为什么你在 componentWillUpdate 中调用 api 而不是 componentDidMount 吗?还分享完整的代码,以便我检查。
  • 我已经更新了包含完整代码的问题。我在componentWillUpdate() 中获取信息,只是因为我在胡闹。它一直在 componentDidMount 并且正在工作。
  • 你的表现不会很好,因为你在 li 标签中使用了多个相同的点击功能。我认为你应该循环并通过 id/value 处理。
  • 你能在沙盒中分享,以便我改进。
  • 很高兴!我该怎么做?你的意思是做一个 Codepen 什么的?

标签: json reactjs rest


【解决方案1】:

为了让您的组件使用更新的数据重新渲染,您需要更新状态变量。

假设您将数据存储在 this.state.results - 但是,您不会在 handleCategory 中更新此状态。

您可以做一些事情:

  • 抽象您的 fetch 调用,使其可重复使用
  • 使用箭头函数摆脱构造函数中的绑定
  • 去掉 componentWillUpdate 生命周期,因为它是多余的
class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isLoading: false,
      results: [],
      error: null,
    };
  }

  fetchData = (url, query, key) => {
    fetch(`the/api/${url}${query}.json?api-key${key}`)
      .then(res => res.ok && res.json())
      .then(data => this.setState({ results: data.results, isLoading: false }))
      .catch(error => this.setState({ error, isLoading: false }));
  }

  componentDidMount() {
    fetchData('api_url', 'all', 'key_here');
  }

  handleCategory = (e) => {
    const cat = e.target.getAttribute('data-facet');
    fetchData('api_url', cat, 'key_here');
  }

  render() {
    const { isLoading, results, error } = this.state;

    if (isLoading) {
      return <div className="loading-icon"></div>
    }

    if (error) {
      return <div className="error"></div>    
    }

    return (
      <div className="wrapper">
        <button data-facet="arts" onClick={this.handleCategory}>Arts</button>
        {results.map(res => ...)}
      </div>
    );
  }
}

【讨论】:

  • 这太好了,谢谢。澄清一下,在componentDidMount 阶段,我是否应该将 api_url、cat 和 key 硬编码为第一次加载的默认值?
  • 当然。您可以回退到默认值,因此在cDM 中您不必使用参数调用。 ES6 有默认参数,所以你可以做 fetchData = (url = 'foo', query = 'all', key = '0') =&gt; ...
猜你喜欢
  • 2021-06-27
  • 1970-01-01
  • 2017-09-15
  • 2020-10-06
  • 2022-01-15
  • 2017-10-13
  • 2019-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多