我在哪里可以使用钩子进行API调用?

问题描述 投票:14回答:4

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

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

但是在React v16.7.0中引入了钩子之后,就没有更多的类组件了。

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

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

javascript reactjs react-native react-hooks
4个回答
28
投票

是的,有一个类似的(但不是相同的!)替换componentDidMount与钩子,它是useEffect钩。

其他答案并没有真正回答您关于API调用位置的问题。您可以使用useEffect进行API调用,并将空数组或对象作为第二个参数传入,以替换componentDidMount()。这里的关键是第二个论点。如果不提供空数组或对象作为第二个参数,则将在每个渲染上调用API调用,它实际上变为componentDidUpdate

如文档中所述:

传入一个空数组[]输入告诉React你的效果不依赖于组件中的任何值,因此该效果只能在mount上运行并在unmount上清理;它不会在更新时运行。

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

API调用严格在Mount上

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

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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

某些支柱/状态发生变化时的API调用

如果您要显示用户的配置文件页面,其中每个页面都具有userID状态/ prop,则应将该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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

你应该阅读useEffect,以便你知道你能做什么/不能做什么。

悬念

正如Dan Abramov在this GitHub Issue上所说:

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

所以请继续关注悬疑!


2
投票

您可以使用为https://resthooks.io提供钩子的库

然后获取您的数据变得如此简单:

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

现在你抓住了id的文章。所有非幸福路径(加载,错误状态)分别由Suspense和Error boundaries处理。

要开始使用这个简单的指南:https://resthooks.io/docs/getting-started/installation

只需7kb gzip,这将为您节省很多痛苦,并且从长远来看,由于重复代码较少,您的捆绑大小会降低。


0
投票

当您使用带有钩子API的功能组件时,您可以使用useEffect()方法来产生副作用。每当由于这些副作用而更新状态时,组件将重新渲染。

Example from the docs.

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视为componentDidMountcomponentDidUpdatecomponentWillUnmount的组合。


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>
  )
}
© www.soinside.com 2019 - 2024. All rights reserved.