在哪里可以通过钩子进行API调用?

时间:2018-11-09 02:43:46

标签: javascript reactjs react-native react-hooks

基本上,我们在类似下面的React类组件的componentDidMount()生命周期方法中进行API调用

     componentDidMount(){
          //Here we do API call and do setState accordingly
     }

但是在React v16.7.0中引入了钩子之后,不再有任何类组件。

我的查询是,我们到底需要在带有钩子的功能组件中进行API调用?

我们有没有类似componentDidMount()的方法?

5 个答案:

答案 0 :(得分:23)

是的,有类似(但不完全相同!)的带有钩子的componentDidMount替代品,它是useEffect钩子。

其他答案并不能真正回答您在哪里可以进行API调用的问题。您可以使用useEffect进行API调用,并传入空数组或对象作为第二个参数来代替componentDidMount()。这里的关键是第二个参数。如果您不提供空数组或对象作为第二个参数,则将在每个渲染器上调用API调用,并且该调用实际上将变为componentDidUpdate

如文档中所述:

  

传入空数组[]会告诉React您的效果不依赖于组件中的任何值,因此该效果仅在安装时运行,而在卸载时清除;它不会在更新上运行。

以下是一些需要进行API调用的场景的示例:

严格在装载上调用API

尝试运行下面的代码并查看结果。

function User() {
  const [firstName, setFirstName] = React.useState(null);
  const [lastName, setLastName] = React.useState(null);
  
  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        const {name} = data.results[0];
        setFirstName(name.first);
        setLastName(name.last);
      });
  }, []); // <-- Have to pass in [] here!

  return (
    <div>
      Name: {!firstName || !lastName ? 'Loading...' : `${firstName} ${lastName}`}
    </div>
  );
}

ReactDOM.render(<User />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

只要属性/状态发生某些更改,API调用

例如,如果要显示某个用户的个人资料页面,其中每个页面都有一个userID状态/属性,则应将该ID作为值传递到useEffect的第二个参数中,以便将数据重新获取新的用户ID。 componentDidMount在这里是不够的,因为如果您直接从用户A转到用户B的个人资料,则可能不需要重新安装组件。

以传统的课堂方式,您可以这样做:

componentDidMount() {
  this.fetchData();
}

componentDidUpdate(prevProps, prevState) {
  if (prevState.id !== this.state.id) {
    this.fetchData();
  }
}

带有钩子的是:

useEffect(() => {
  this.fetchData();
}, [id]);

尝试运行以下代码,然后查看结果。例如,将id更改为2,以查看useEffect再次运行。

function Todo() {
  const [todo, setTodo] = React.useState(null);
  const [id, setId] = React.useState(1);
  
  React.useEffect(() => {
    if (id == null || id === '') {
      return;
    }
    
    fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
      .then(results => results.json())
      .then(data => {
        setTodo(data);
      });
  }, [id]); // useEffect will trigger whenever id is different.

  return (
    <div>
      <input value={id} onChange={e => setId(e.target.value)}/>
      <br/>
      <pre>{JSON.stringify(todo, null, 2)}</pre>
    </div>
  );
}

ReactDOM.render(<Todo />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.8.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.8.1/umd/react-dom.development.js"></script>

<div id="app"></div>

您应该阅读useEffect,以便了解您可以/不能使用它。

暂记

如丹·阿布拉莫夫(Dan Abramov)在this GitHub Issue上所说:

  

从长远来看,我们将不鼓励这种(useEffect)模式,因为它会鼓励比赛条件。例如-在通话开始和结束之间可能会发生任何事情,并且您可能会获得新的道具。相反,我们建议使用Suspense进行数据提取

所以请继续关注悬念!

答案 1 :(得分:2)

您可以使用像https://resthooks.io

这样的库来为您提供钩子

然后获取数据变得非常简单:

const article = useResource(ArticleResource.singleRequest(), { id });

现在,您通过ID抓取了这篇文章。所有不满意的路径(加载,错误状态)分别由Suspense和Error boundaries处理。

要开始使用,请遵循以下简单指南:https://resthooks.io/docs/getting-started/installation

只需压缩7kb压缩包,这将为您节省很多痛苦,并且从长远来看,由于重复代码较少,因此可以减小捆绑包的大小。

答案 2 :(得分:2)

我只是将其发布为了解acc的一种简单方法。我的努力归功于Yangshun Tay的帖子,它涵盖了几乎所有内容。

安装组件时的API调用

代码:

  useEffect(() => { 
    // here is where you make API call(s) or any side effects
    fetchData('/data')
  }, [] ) /** passing empty braces is necessary */

因此,在组件创建(装入)和销毁(卸下)时,useEffect(fn,[])与空参数一起用作[]会使fn()触发一次值。

专业提示:

此外,如果您在此return()fn进行某些操作,则它的生命周期与类组件的生命周期相同。

componentWillUnmount()

某些值更改时的API调用

如果您希望在某些值更改时调用API,只需将该变量(存储值)传递到 useEffect(() => { fetchData('/data') return () => { // this will be performed when component will unmount resetData() } }, [] ) 中的arguments数组中。

useEffect()

这将确保每当 useEffect(() => { // perform your API call here updateDetails(); },[prop.name]) /** --> will be triggered whenever value of prop.name changes */ 的值更改时,挂钩中的函数都会被触发。

还要注意:该钩子在安装组件时也会首先被调用。因此,那时您的名称值可能处于初始状态,这在您看来是意外的。因此,您可以在函数中添加自定义条件,以避免不必要的API调用。

答案 3 :(得分:0)

将功能组件与hooks API一起使用时,可以使用useEffect()方法产生副作用。由于这些副作用,无论何时更新状态,组件都会重新渲染。

文档中的示例。

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

例如,您可以在异步请求的回调函数中调用setCount。当执行回调时,状态将被更新,React将重新渲染组件。同样来自文档:

  

提示

     

如果您熟悉React类的生命周期方法,可以考虑   useEffect Hook的componentDidMountcomponentDidUpdate和   componentWillUnmount组合。

答案 4 :(得分:0)

您也可以像这样使用use-http

import useFetch from 'use-http'

function App() {
  // add whatever other options you would add to `fetch` such as headers
  const options = {
    method: 'POST',
    body: {}, // whatever data you want to send
  }

  var [data, loading, error] = useFetch('https://example.com', options)

  // want to use object destructuring? You can do that too
  var { data, loading, error } = useFetch('https://example.com', options)

  if (error) {
    return 'Error!'
  }

  if (loading) {
    return 'Loading!'
  }

  return (
    <code>
      <pre>{data}</pre>
    </code>
  )
}