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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53219113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:08:34  来源:igfitidea点击:

Where can I make API call with hooks in react?

javascriptreactjsreact-nativereact-hooks

提问by Hemadri Dasari

Basically we do API calls in componentDidMount()life cycle method in React class components like below

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

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

But after hooks are introduced in React v16.7.0, its all like functional components mostly

但是在 React v16.7.0 引入 hooks 之后,基本上都是函数式组件

My query is, where exactly do we need to make API call in functional component with hooks?

我的问题是,我们究竟需要在哪里使用钩子在功能组件中进行 API 调用?

Do we have any method for it similar like componentDidMount()?

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

回答by Yangshun Tay

Yes, there's a similar (but not the same!) substitute for componentDidMountwith hooks, and it's the useEffecthook.

是的,有一个类似(但不一样!)的替代品componentDidMountwith 钩子,它是useEffect钩子。

The other answers don't really answer your question about where you can make API calls. You can make API calls by using useEffectand passing in an empty array or object as the second argumentas a replacement for componentDidMount(). The key here is the second argument. If you don't provide an empty array or object as the second argument, the API call will be called on every render, and it effectively becomes a componentDidUpdate.

其他答案并没有真正回答您关于可以在哪里进行 API 调用的问题。您可以通过使用useEffect传入一个空数组或对象作为第二个参数来替代componentDidMount(). 这里的关键是第二个参数。如果您不提供空数组或对象作为第二个参数,API 调用将在每次渲染时调用,它实际上变成了一个componentDidUpdate.

As mentioned in the docs:

如文档中所述:

Passing in an empty array [] of inputs tells React that your effect doesn't depend on any values from the component, so that effect would run only on mount and clean up on unmount; it won't run on updates.

传入一个空数组 [] 的输入告诉 React 你的效果不依赖于组件的任何值,所以效果只会在安装时运行并在卸载时清理;它不会在更新上运行。

Here are some examples for scenarios where you will need to make API calls:

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

API Call Strictly on Mount

严格在挂载上调用 API

Try running the code below and see the result.

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

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 Call Whenever Some Prop/State Changes

每当某些 Prop/State 更改时调用 API

If you are for example displaying a profile page of a user where each page has a userID state/prop, you should pass in that ID as a value into the second parameter of useEffectso that the data will be refetched for a new user ID. componentDidMountis insufficient here as the component might not need remounting if you go directly from user A to user B's profile.

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

In the traditional classes way, you would do:

在传统的类方式中,你会这样做:

componentDidMount() {
  this.fetchData();
}

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

With hooks, that would be:

使用钩子,那将是:

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

Try running the code below and see the result. Change the id to 2 for instance to see that useEffectis run again.

尝试运行下面的代码并查看结果。例如,将 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>

You should read up on useEffectso that you know what you can/cannot do with it.

你应该仔细阅读,useEffect这样你就知道你可以/不能用它做什么。

Suspense

悬念

As Dan Abramov said on this GitHub Issue:

正如 Dan Abramov 在这个 GitHub 问题上所说:

Longer term we'll discourage this (useEffect) pattern because it encourages race conditions. Such as — anything could happen between your call starts and ends, and you could have gotten new props. Instead, we'll recommend Suspense for data fetching

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

So stay tuned for Suspense!

所以请继续关注悬念!

回答by Nathaniel Tucker

You can use a library that provides the hooks for you like https://resthooks.io

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

Then getting your data becomes as simple as:

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

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

Now you grabbed the article by id. All non-happy paths (loading, error states) are handled by Suspense and Error boundariesrespectively.

现在您通过 id 抓取了文章。所有非快乐路径(加载、错误状态)分别由 Suspense 和Error 边界处理。

To get started follow this simple guide: https://resthooks.io/docs/getting-started/installation

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

At only 7kb gzipped this will save you a lot of pain and in the long run lower your bundle size due to less repeated code.

压缩后只有 7kb,这将为您节省很多痛苦,并且从长远来看,由于重复代码较少,可以降低包的大小。

回答by Alex Cory

You could also use use-httplike:

你也可以使用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>
  )
}

回答by Donny Verduijn

When you are using functional components with the hooks API, you can use the useEffect()method to produce side effects. Whenever the state is updated because of these side effects, the component will re-render.

当您使用带有钩子 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>
  );
}

For example, you could call setCountin a callback function of an async request. When the callback is executed, the state will get updated and React will re-render the component. Also from the docs:

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

Tip

If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmountcombined.

小费

如果你熟悉阵营类生命周期方法,你能想到useEffect挂钩作为componentDidMountcomponentDidUpdatecomponentWillUnmount合并。