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

Hem*_*ari 28 javascript reactjs react-native react-hooks

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

     componentDidMount(){
          //Here we do API call and do setState accordingly
     }
Run Code Online (Sandbox Code Playgroud)

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

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

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

Yan*_*Tay 49

是的,有一个类似的(但不一样!)替换为componentDidMount钩子,它是useEffect钩子.

其他答案并没有真正回答您关于API调用位置的问题.您可以通过使用useEffect传入一个空数组或对象作为第二个参数作为替代来进行API调用componentDidMount().这里的关键是第二个论点.如果不提供空数组或对象作为第二个参数,则将在每个渲染上调用API调用,并且它实际上变为a 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'));
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

componentDidMount() {
  this.fetchData();
}

componentDidUpdate(prevProps, prevState) {
  if (prevState.id !== this.state.id) {
    this.fetchData();
  }
}
Run Code Online (Sandbox Code Playgroud)

使用钩子,那将是:

useEffect(() => {
  this.fetchData();
}, [id]);
Run Code Online (Sandbox Code Playgroud)

尝试运行下面的代码并查看结果.例如,将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'));
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

悬念

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

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

所以请继续关注悬疑!


Nat*_*ker 8

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

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

const article = useResource(ArticleResource.detail(), { id });
Run Code Online (Sandbox Code Playgroud)

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

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

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


Mee*_*eri 5

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

组件安装的 API 调用

代码:

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

因此,当组件创建(挂载)和销毁(卸载)时,使用useEffect(fn,[])空参数作为[]使fn()触发一次,而不依赖于任何值。

专家提示:

此外,如果您return()对此有所了解,fn那么它将componentWillUnmount()与类组件的生命周期相同。

  useEffect(() => { 
   fetchData('/data')
   return () => {
    // this will be performed when component will unmount
    resetData()
   }
  }, [] )
Run Code Online (Sandbox Code Playgroud)

某些值更改时调用 API

如果您希望在某些值更改时调用 API,只需将该变量(存储值)传递到useEffect().

 useEffect(() => {
  // perform your API call here
  updateDetails();
 },[prop.name]) /** --> will be triggered whenever value of prop.name changes */
Run Code Online (Sandbox Code Playgroud)

这将确保每当值发生prop.name变化时,钩子中的函数都会被触发。

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