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

目录
  • 介绍一下API
  • fetch()方法访问API
  • setState的副作用
  • 使用useEffect解决这个问题
  • 使用useEffect操控函数运行

介绍一下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的资料请关注我们其它相关文章!

(0)

相关推荐

  • React useEffect异步操作常见问题小结

    目录 三个常见的问题: 一.react hooks发异步请求 二.如何在组件加载的时候发起异步任务 三.如果在响应回来之前组件被销毁了会怎样? 四.如何在组件交互时发起异步任务 为什么两种写法会有差异呢? 五.其他陷阱 总结 useEffect 和异步任务搭配使用的时候会遇到的一些坑总结. 三个常见的问题: 1.如何在组件加载的时候发起异步任务 2.如何在组件交互的时候发起异步任务 3.其他陷阱 一.react hooks发异步请求 1.使用useEffect发起异步任务,第二个参数使用空数组可

  • react中使用useEffect及踩坑记录

    目录 使用useEffect及踩坑记录 useEffect 介绍 useEffect常见跳坑 hooks中useEffect()使用总结 常见使用 useEffect() 的第二个参数说明 useEffect() 第一个函数参数的返回值 useEffect() 的注意点 使用useEffect及踩坑记录 useEffect 介绍 useEffect时reactHook中最重要,最常用的hook之一. useEffect相当于react中的什么生命周期呢? 这个问题在react官网中有过介绍,在使

  • react中的watch监视属性-useEffect介绍

    目录 react的watch监视属性-useEffect useEffect使用指南 最基本的使用 响应更新 如何处理Loading和Error 处理表单 自定义hooks 使用useReducer整合逻辑 取消数据请求 react的watch监视属性-useEffect 在vue中可以使用watch属性,去监视一个值,当这个值进行变化的时候就去执行一些操作.在react是没有这个属性的,但是它也一样可以达到相同的效果,那么接下来看看它是怎么实现的呢? 在react中实现监听效果有一个比较简单的

  • 如何解决React useEffect钩子带来的无限循环问题

    目录 什么导致的无限循环以及如何解决它们 如何解决这个问题 使用函数作为依赖项 使用数组作为依赖项 将对象作为依赖项传递 传递不正确的依赖项 结尾 React的useEffect Hook可以让用户处理应用程序的副作用.例如: 从网络获取数据:应用程序通常在第一次加载时获取并填充数据.这可以通过useEffect函数实现 操作UI:应用程序应该响应按钮点击事件(例如,打开一个菜单) 设置或结束计时器:如果某个变量达到预定义值,则内置计时器应自行停止或启动 尽管useEffect Hook在Rea

  • useEffect理解React、Vue设计理念的不同

    目录 引言 Vue与React的差异 useEffect会越来越复杂 总结 引言 我们知道,React发布Hooks后,带来了业界一波Hooks热.很多框架(比如Vue Composition API.Solid.js)都借鉴了Hooks的模式. 但是,即使这些框架都借鉴了Hooks,但由于框架作者的理念不同,发展方向也逐渐不同. 比如,在Vue Composition API中,对标React useEffect API的是watchEffect,在Vue文档中,有一小段内容介绍他的用法: 而

  • React useEffect不支持async function示例分析

    目录 引言 React为什么这么设计呢? 简单改造 1.简单改造的写法(不推荐) 2.把异步提取成单独函数或自定义hook(推荐) 引言 useEffect相比大家都耳熟能详啦,如下这种写法,应该是非常常见的需求. useEffect(async () => { await getPoiInfo(); // 请求数据 }, []); 但是 React 本身并不支持这么做,理由是 effect function 应该返回一个销毁函数(effect:是指return返回的cleanup函数),如果

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

    目录 介绍一下API fetch()方法访问API setState的副作用 使用useEffect解决这个问题 使用useEffect操控函数运行 介绍一下API 本文主要内容:描述了setState与fetch之间产生的冲突副作用,并使用useEffect进行解决 API,即Application Programming Interface,应用程序接口,是很多程序向开发人员提供的易于使用的抽象化的代码. 比如经常会用到的查询天气API,智能识图API,如果是直接照着复杂的代码编写,会相当不

  • React高阶组件使用教程详解

    目录 高阶组件(HOC) 概述 使用HOC解决横切关注点问题 不用改变原始组件使用组合 约定-将不相关的 props 传递给被包裹的组件 约定-最大化可组合性 约定-包装显示名称以便轻松调试 使用高阶组件的注意事项 高阶组件(HOC) 概述 是React复用组件逻辑的一种高级技巧,是一种基于React组合特性而形成的设计模式 高阶组件是参数为组件,返回值为新组件的函数 简单理解: 高阶组件本身是 函数,传参数是组件,返回值也是组件: 高阶组件不用关心数据是如何渲染的,只用关心逻辑即可 被包装的组

  • React中useLayoutEffect钩子使用场景详解

    目录 简介 useEffect钩子的概述 钩子流程 useLayoutEffect钩子的概述 钩子流程 什么时候使用useLayoutEffect钩子? 总结 简介 不久前,React对其功能组件进行了一次重大更新(在2019年3月的16.8版本中),终于为这些组件提供了一种变得有状态的方法. 钩子的加入不仅意味着功能组件将能够提供自己的状态,而且还能通过引入useEffect钩子来管理自己的生命周期事件. 此外,这次更新还引入了一个全新的useLayoutEffect钩子,根据React文档,

  • react redux及redux持久化示例详解

    目录 一.react-redux 二.redux持久化 一.react-redux react-redux依赖于redux工作. 运行安装命令:npm i react-redux: 使用: 将Provider套在入口组件处,并且将自己的store传进去: import FilmRouter from './FilmRouter/index' import {Provider} from 'react-redux' import store from './FilmRouter/views/red

  • react编写可编辑标题示例详解

    目录 需求 初始需求 方案设计 方案一 span + contentEditable 思路 代码如下 在这个方案中遇到的问题 存在的问题 方案二 直接用input处理展示和编辑 踩到的坑 需求 因为自己换工作到了新公司,上周入职,以前没有使用过react框架,虽然前面有学习过react,但是并没有实践经验 这个需求最终的效果是和石墨标题修改实现一样的效果 初始需求 文案支持可编辑 用户点击位置即光标定位处 超过50字读的时候,超出部分进行截断 当用户把所有内容删除时,失去焦点时文案设置为 “无文

  • React Context源码实现原理详解

    目录 什么是 Context Context 使用示例 createContext Context 的设计非常特别 useContext useContext 相关源码 debugger 查看调用栈 什么是 Context 目前来看 Context 是一个非常强大但是很多时候不会直接使用的 api.大多数项目不会直接使用 createContext 然后向下面传递数据,而是采用第三方库(react-redux). 想想项目中是不是经常会用到 @connect(...)(Comp) 以及 <Pro

  • React Native系列之Recyclerlistview使用详解

    目录 recyclerlistview的介绍与使用 1.安装 2.概述和功能 3. RecyclerListView的使用 1.dataProvider 2.LayoutProvider 3.rowRenderer 4.onEndReached 5.onEndReachedThreshold 6.extendedState 7.scrollViewProps RecyclerListView所有属性 recyclerlistview的介绍与使用 1.安装 npm install --save r

  • react后台系统最佳实践示例详解

    目录 一.中后台系统的技术栈选型 1. 要做什么 2. 要求 3. 技术栈怎么选 二.hooks时代状态管理库的选型 context redux recoil zustand MobX 三.hooks的使用问题与解决方案 总结 一.中后台系统的技术栈选型 本文主要讲三块内容:中后台系统的技术栈选型.hooks时代状态管理库的选型以及hooks的使用问题与解决方案. 1. 要做什么 我们的目标是搭建一个适用于公司内部中后台系统的前端项目最佳实践. 2. 要求 由于业务需求比较多,一名开发人员需要负

  • react中的ajax封装实例详解

    react中的ajax封装实例详解 代码块 **opts: {'可选参数'} **method: 请求方式:GET/POST,默认值:'GET'; **url: 发送请求的地址, 默认值: 当前页地址; **data: string,json; **async: 是否异步:true/false,默认值:true; **cache: 是否缓存:true/false,默认值:true; **contentType: HTTP头信息,默认值:'application/x-www-form-urlenc

  • 利用CDN加速react webpack打包后的文件详解

    此文不介绍webpack基本配置,如果对基本配置有疑问请查阅官方文档. 1.配置webpack.config.js 将output.publicPath改成上传到的cdn地址, 例(对应上面上传配置): publicPath: "https://your_base_cdn_url" + process.env.NODE_ENV + "/cdn/" 打包 NODE_ENV=production node_modules/webpack/bin/webpack.js -

随机推荐