React使用useEffect解决setState副作用详解

 更新时间:2022年10月26日 16:37:01   作者:heheer  
这篇文章主要为大家介绍了React使用useEffect解决setState副作用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

介绍一下API

本文主要内容:描述了setState与fetch之间产生的冲突副作用,并使用useEffect进行解决

API,即Application Programming Interface,应用程序接口,是很多程序向开发人员提供的易于使用的抽象化的代码。

比如经常会用到的查询天气API,智能识图API,如果是直接照着复杂的代码编写,会相当不友好。而API则只需按照它们提供的规则即可简单、方便、安全地使用。

fetch()方法访问API

我们会用到一个很简单的资源API,https://swapi.dev/api/people/1,这是一个会返回星球大战里的人物信息的API。

所以我们要做的事:1、读取API中提供的数据; 2、将获得的数据写入state。

首先我们来做第一步,这里介绍一下fetch()

fetch() 必须接受一个参数——资源的路径。无论请求成功与否,它都返回一个 Promise 对象,resolve 对应请求的Response。

一旦 Response被返回,就可以使用一些方法来定义内容的形式

所以我们可以使用以下代码完成资源API的读取,并且渲染到页面上

import React from "react"
export default function App() {
    const [starWarsData, setStarWarsData] = React.useState({})
    fetch("https://swapi.dev/api/people/1")
        .then(res => res.json())
        .then(data => setStarWarsData(data))
    return (
        <div>
            <pre>{JSON.stringify(starWarsData, null, 2)}</pre>
        </div>
    )
}

可以看到我们似乎确实轻松地获得了资源接口所提供给我们的数据

然而当我们加上控制台的输出后,事情就变得不一样了

setState的副作用

在这个程序中,我们可以加上一句console.log在控制台输出后天的运行情况,如下

import React from "react"
export default function App() {
    const [starWarsData, setStarWarsData] = React.useState({})
    console.log("component rendered")
    fetch("https://swapi.dev/api/people/1")
        .then(res => res.json())
        .then(data => setStarWarsData(data))
    return (
        <div>
            <pre>{JSON.stringify(starWarsData, null, 2)}</pre>
        </div>
    )
}

这时再运行就能清楚地看到在控制台处显示了这个组件在一直不断地生成,重新地render

我们可以简单地分析一下原因,

  • 组件每次render都会触发一次fetch,
  • 然后fetch获取的数据传入setState又会重新使得组件被render一遍,

而这就形成了一个死循环,致使组件不断地生成。

使用useEffect解决这个问题

useEffect()出现之前,react并没有setState后停止render的方法,这就使得setState的使用需要非常谨慎,不过如今提供了useEffet()来解决这个问题

useEffect接受两个参数,其中第二个参数是可选的

useEffect(<function>, <dependency array>)

所以让我们先来尝试一下不使用第二个参数会得到什么结果

import React from "react"
export default function App() {
    const [starWarsData, setStarWarsData] = React.useState({})
    console.log("component rendered")
    React.useEffect(function(){
        fetch("https://swapi.dev/api/people/1")
            .then(res => res.json())
            .then(data => setStarWarsData(data))
    })
    return (
        <div>
            <pre>{JSON.stringify(starWarsData, null, 2)}</pre>
        </div>
    )
}

可以看到在上面的代码里我们已经按照语法要求使用了useEffect(),然而结果却不如我们所设想的只打印一条语句,依旧是一个死循环

原因在于只使用一个参数的useEffect()的效果是在组件被挂载被更新两种情况下执行参数的函数,所以并不能解决更新状态不执行的效果

那么就要用到第二个参数了,第二个参数叫做dependency array,只有在这个数组里的元素更新了,才会触发这个useEffect

所以这里我们可以将第二个参数设置为一个空数组,这样只有在组件刚刚被挂载的时候才会执行useEffect,很好的解决了我们只需要读取一遍API的任务要求

import React from "react"
export default function App() {
    const [starWarsData, setStarWarsData] = React.useState({})
    console.log("component rendered")
    React.useEffect(function(){
        fetch("https://swapi.dev/api/people/1")
            .then(res => res.json())
            .then(data => setStarWarsData(data))
    }, [])
    return (
        <div>
            <pre>{JSON.stringify(starWarsData, null, 2)}</pre>
        </div>
    )
}

使用useEffect操控函数运行

dependency array我们也可以得出另一种用法,可以看以下代码

import React from "react"
export default function App() {
    const [count, setCount] = React.useState(0)
    console.log("Component rendered")
    React.useEffect(() => {
        console.log("Effect function ran")
    }, [count])
    return (
        <div>
            <h2>The count is {count}</h2>
            <button onClick={() => setCount(prevCount => prevCount + 1)}>Add</button>
        </div>
    )
}

我们在第二个参数处填入了会随着我们点击而变化的count,所以在我们每次点击使得count增加以后,count state发生变化,执行useEffect第一个参数的函数

可以看到设置了count state,再在useEffect中设置countdependency,这样每次改变count的值就会再一次执行useEffect中的函数。

以上就是React使用useEffect解决setState副作用详解的详细内容,更多关于React useEffect解决setState的资料请关注脚本之家其它相关文章!

相关文章

  • react配合antd组件实现的管理系统示例代码

    react配合antd组件实现的管理系统示例代码

    这篇文章主要介绍了react配合antd组件实现的管理系统示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • 简单的React SSR服务器渲染实现

    简单的React SSR服务器渲染实现

    这篇文章主要介绍了简单的React SSR服务器渲染实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • React-redux实现小案例(todolist)的过程

    React-redux实现小案例(todolist)的过程

    这篇文章主要为大家详细介绍了React-redux实现小案例(todolist)的过程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • React中this丢失的四种解决方法

    React中this丢失的四种解决方法

    这篇文章主要给大家介绍了关于React中this丢失的四种解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者使用React具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • 如何将你的AngularJS1.x应用迁移至React的方法

    如何将你的AngularJS1.x应用迁移至React的方法

    本篇文章主要介绍了如何将你的AngularJS1.x应用迁移至React的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • react.js 获取真实的DOM节点实例(必看)

    react.js 获取真实的DOM节点实例(必看)

    下面小编就为大家带来一篇react.js 获取真实的DOM节点实例(必看)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • React中组件复用的方式总结

    React中组件复用的方式总结

    这篇文章主要为大家详细介绍了Mixin、HOC、Render Props、Hooks这四种组件间复用的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-06-06
  • ahooks useRequest源码精读解析

    ahooks useRequest源码精读解析

    这篇文章主要为大家介绍了ahooks useRequest的源码精读解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • React封装CustomSelect组件思路详解

    React封装CustomSelect组件思路详解

    小编需要封装一个通过Popover弹出框里可以自定义渲染内容的组件,渲染内容暂时有: 单选框, 复选框,接下来通过本文给大家分享React封装CustomSelect组件思路,需要的朋友可以参考下
    2022-07-07
  • react嵌套路由实现TabBar的实现

    react嵌套路由实现TabBar的实现

    本文主要介绍了react嵌套路由实现TabBar的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08

最新评论