• Hooks进阶--useEffect - 发送网络请求


    1.useState - 回调函数的参数

    使用场景

    参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过计算才能获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用

    语法

    const [name, setName] = useState(()=>{    // 编写计算逻辑    return '计算之后的初始值'})
    

    语法规则

    1. 回调函数return出去的值将作为 name 的初始值
    2. 回调函数中的逻辑只会在组件初始化的时候执行一次

    语法选择

    1. 如果就是初始化一个普通的数据 直接使用 useState(普通数据) 即可
    2. 如果要初始化的数据无法直接得到需要通过计算才能获取到,使用useState(()=>{})

    eg。

    1. import { useState } from 'react'
    2. // 计算的含义
    3. function getDefaultValue(){
    4. for(let i =0 ;i<1000;i++){
    5. }
    6. return '10'
    7. }
    8. function Counter(props) {
    9. const [count, setCount] = useState(() => {
    10. // 这里目的:为了体现初始值经过一定的计算
    11. // 这个计算比较广义的概念
    12. // 只要无法直接确定,需要通过一定的操作才能获取,
    13. // 就可以理解为计算
    14. // 循环遍历一万条数据,才能确定这里的初始值是什么
    15. return props.count
    16. ------------------------
    17. return getDefaultValue()
    18. })
    19. return (
    20. <div>
    21. <button onClick={() => setCount(count + 1)}>{count}button>
    22. div>
    23. )
    24. }
    25. function App() {
    26. return (
    27. <>
    28. <Counter count={10} />
    29. <Counter count={20} />
    30. )
    31. }
    32. export default App

    2.useEffect - 清理副作用

    有一些副作用是需要清除的,可以防止引起内存泄露。

    1.使用场景

    在组件被销毁时,如果有些副作用操作需要被清理,就可以使用此语法,比如常见的定时器

    2.语法及规则

    1. useEffect(() => {
    2. console.log('副作用函数执行了')
    3. // 副作用函数的执行时机为: 在下一次副作用函数执行之前执行
    4. return () => {
    5. console.log('清理副作用的函数执行了')
    6. // 在这里写清理副作用的代码
    7. }
    8. })

    3.代码复现:

    1. import { useEffect, useState } from 'react'
    2. function Test () {
    3. //清除副作用effect
    4. useEffect(() => {
    5. let timer = setInterval(() => {
    6. console.log('定时器执行了')
    7. }, 1000)
    8. return () => {//执行时机:React将会在执行清除操作时调用它--componentWillMount
    9. //清理的动作
    10. clearInterval(timer)
    11. }
    12. }, [])
    13. return (
    14. <div>this is testdiv>
    15. )
    16. }
    17. function App () {
    18. const [flag, setFlag] = useState(true)
    19. return (
    20. <>
    21. {flag ? <Test /> : null}
    22. <button onClick={() => setFlag(!flag)}>switchbutton>
    23. )}

    将setFlag作为函数书写的案例:

    1. import { useEffect, useState } from 'react'
    2. function A () {
    3. useEffect(() => {
    4. let timer = setInterval(() => {
    5. console.log(111)
    6. }, 1000)
    7. return () => {
    8. clearInterval(timer)
    9. }
    10. })
    11. return (
    12. <div>
    13. A组件
    14. div>
    15. )
    16. }
    17. function App () {
    18. const [isShow, setIsShow] = useState(true)
    19. function changeA () {
    20. setIsShow(false)
    21. }
    22. return (
    23. <div>
    24. {isShow ? <A /> : null}
    25. <button onClick={changeA}>销毁A组件button>
    26. div>
    27. )}

    3.定时器小案例

    添加副作用函数前:组件虽然已经不显示了,但是定时器依旧在运行

    1. import { useEffect, useState } from 'react'
    2. function Foo() {
    3. useEffect(() => {
    4. setInterval(() => {
    5. console.log('副作用函数执行了')
    6. }, 1000)
    7. })
    8. return <div>Foodiv>
    9. }
    10. function App() {
    11. const [flag, setFlag] = useState(true)
    12. return (
    13. <>
    14. <button onClick={() => setFlag(false)}>clickbutton>
    15. {flag ? <Foo/> : null}
    16. )
    17. }
    18. export default App

    添加清理副作用函数后:一旦组件被销毁,定时器也被清理

    1. import { useEffect, useState } from 'react'
    2. function Foo() {
    3. useEffect(() => {
    4. const timerId = setInterval(() => {
    5. console.log('副作用函数执行了')
    6. }, 1000)
    7. // 添加清理副租用函数
    8. return () => {
    9. clearInterval(timerId)
    10. }
    11. })
    12. return <div>Foodiv>
    13. }
    14. function App() {
    15. const [flag, setFlag] = useState(true)
    16. return (
    17. <>
    18. <button onClick={() => setFlag(false)}>clickbutton>
    19. {flag ? <Foo/> : null}
    20. )
    21. }
    22. export default App

    4.useEffect - 发送网络请求

    类组件如何发送网络请求?

    发送网络请求的生命周期钩子函数:componentDidMount

    执行时机?

    在初始化的时候dom渲染完毕时,只执行一次

    useEffect

    • 不加依赖项 - 初始化 + 重新渲染
    • 加[ ] - 初始化执行一次
    • 加特定的依赖项[count,name] - 首次执行 +任意一个变化执行

    1.使用场景

    如何在useEffect中发送网络请求,并且封装同步 async await操作

    2.语法要求

    不可以直接在useEffect的回调函数外层直接包裹 await ,因为异步会导致清理函数无法立即返回

    1. useEffect(async ()=>{
    2. const res = await axios.get('http://geek.itheima.net/v1_0/channels')
    3. console.log(res)
    4. },[])

    3.正确写法

    在内部单独定义一个函数,然后把这个函数包装成同步

    1. useEffect(()=>{
    2. async function fetchData(){
    3. // await fetch也可以,百度搜索
    4. const res = await axios.get('http://geek.itheima.net/v1_0/channels')
    5. console.log(res)
    6. }
    7. },[])

    复制一张图片的地址,可以将图片请求出来:

    1. function A () {
    2. const [imgs, setImgs] = useState('')
    3. useEffect(() => {
    4. const res = fetch('https://fastly.jsdelivr.net/npm/@vant/assets/logo.png')
    5. console.log(res)
    6. res.then((value) => {
    7. console.log(value)//返回的是一个结果
    8. setImgs(value.url)
    9. })
    10. },[])
    11. return (
    12. <div>
    13. A组件
    14. <img src={imgs} alt="" />
    15. div>
    16. )}

     

    useEffect发送网络请求,只请求一次的话,依赖项就设置为空数组 。

    5.useRef

    useRef获取真实dom或组件实例。返回一个可变的ref对象,其中.current属性被初始化为传入的参数,

    1.使用场景

    在函数组件中获取真实的dom元素对象或者是组件对象

    2.使用步骤

    1. 导入 useRef 函数
    2. 执行 useRef 函数并传入null,返回值为一个对象 内部有一个current属性存放拿到的dom对象(组件实例)
    3. 通过ref 绑定 要获取的元素或者组件

    3.获取dom

    1. import { useEffect, useRef } from 'react'
    2. class Test extends React.Component {
    3. render () {
    4. return (
    5. <div>类组件div>
    6. )
    7. }
    8. }
    9. function App() {
    10. const testRef = useRef(null)
    11. const h1Ref = useRef(null)
    12. //useEffect回调:在dom渲染之后
    13. // vue里的watch效果比较像,但执行时机时不同的
    14. useEffect(() => {
    15. console.log(testRef.current)
    16. console.log(h1Ref.current)
    17. console.log(h1Ref)
    18. },[])
    19. return (
    20. <div>
    21. <Test ref={testRef} />
    22. <h1 ref={ h1Ref }>this is h1h1>
    23. div>
    24. )
    25. }
    26. export default App

    在Test中加入函数,state等

    1. state={
    2. name:'zz'
    3. }
    4. getName=()=>{
    5. return 'child test'
    6. }

    4.获取组件实例

    函数组件由于没有实例,不能使用ref获取,如果想获取组件实例,必须是类组件

    Foo.js

    1. class Foo extends React.Component {
    2. sayHi = () => {
    3. console.log('say hi')
    4. }
    5. render(){
    6. return <div>Foodiv>
    7. }
    8. }
    9. export default Foo

    App.js

    1. import { useEffect, useRef } from 'react'
    2. import Foo from './Foo'
    3. function App() {
    4. const h1Foo = useRef(null)
    5. useEffect(() => {
    6. console.log(h1Foo)
    7. }, [])
    8. return (
    9. <div> <Foo ref={ h1Foo } />div>
    10. )
    11. }
    12. export default App

    5.useContext

    在函数组件中跨组件通信 

    • 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。
    • 当前的 context 值由上层组件中距离当前组件最近的  的 value prop 决定。 

    1.实现步骤

    1. 使用createContext 创建Context对象
    2. 在顶层组件通过Provider 提供数据
    3. 在底层组件通过useContext函数获取数据

    2.代码实现

    1. import { createContext, useContext } from 'react'
    2. // 1.创建Context对象
    3. const Context = createContext()
    4. function Foo() {
    5. return <div>Foo <Bar/>div>
    6. }
    7. function Bar() {
    8. // 3.底层组件通过useContext函数获取数据
    9. // usseContext(createContext返回的对象)
    10. //通过调用useContext,将Context对象传过去,得到当前的传过去的Context的值
    11. const name = useContext(Context)
    12. return <div>Bar {name}div>
    13. }
    14. function App() {
    15. return (
    16. // 2.顶层组件通过Provider 提供数据
    17. <Context.Provider value={'this is name'}>
    18. <div><Foo/>div>
    19. Context.Provider>
    20. )
    21. }
    22. export default App

    3.单独写

    1.把createContext分装出去,创建context.js ---要记得都保存

    1. import { createContext } from "react"
    2. const Context = createContext()
    3. export default Context

    2.App.js引用context.js

    import Context from './context'
    

    完整代码:

    1. import React, { useContext, useState } from 'react'
    2. import Context from './context'
    3. function ComA () {
    4. const count = useContext(Context)
    5. return (
    6. <div>
    7. ComA
    8. <br />
    9. app传过来的数据为:{count}
    10. <ComC />
    11. div>
    12. )
    13. }
    14. function ComC () {
    15. const count = useContext(Context)
    16. return (
    17. <div>
    18. ComC
    19. <br />
    20. app传过来的数据为:{count}
    21. div>
    22. )
    23. }
    24. function App () {
    25. const [count, setCount] = useState(20)
    26. return (
    27. <Context.Provider value={count}>
    28. <div>
    29. <ComA />
    30. <button onClick={() => { setCount(count + 1) }}>+button>
    31. div>
    32. Context.Provider>
    33. )
    34. }
    35. export default App

    4.也可以在index.js中使用createContext

    1.index.js中引入context.js

    import Context from './context'
    

    2.除去App.js中的以下内容

    1. <Context.Provider value={count}>
    2. const [count, setCount] = useState(20)

    3.index.js中添加

    1. <React.StrictMode>
    2. // 这个value只能传递一次,是什么就是什么
    3. <Context.Provider value={100}>
    4. <App />
    5. Context.Provider>
    6. React.StrictMode>,

    context如果要传递的数据,只需要在整个应用初始化的时候传递一次就可以,可以选择在当前文件里做数据提供,index.js->静态的

    context如果需要传递数据并且将来还需要再对数据做修改,底层组件也需要变,所以可以写到App.js中->动态的

    阶段小练习-todoMvc-hook版

    案例仓库地址:

    react课程全系列/react-tomvc-hook

    项目演示步骤:

    1. 克隆项目到本地
      git clone  https://gitee.com/react-course-series/react-tomvc-hook.git
      
    2. 安装必要依赖
      yarn
      
    3. 开启mock接口服务,保持窗口不关闭 !!!!!
      1. # 启动mock服务
      2. yarn mock-serve
    4. 另起一个bash窗口开启前端服务
      yarn start
      
    5. 浏览器输入 localhost:3000演示效果

    项目开发步骤:

    1. 切换到todo-test分支

      git checkout todo-test
      
    2. 打开 app.js

      已有基础样板代码,在这个基础上编写业务逻辑即可

    3. 接口文档

      接口作用接口地址接口方法接口参数
      获取列表http://localhost:3001/dataGET
      删除http://localhost:3001/data/:idDELETEid
      搜索http://localhost:3001/data/?q=keywordGETname(以name字段搜索)

    实现功能

    功能核心思路
    表格数据渲染elementPlus el-table组件使用
    删除功能获取当前id 调用接口
    搜索功能用的依旧是列表接口,多传一个name参数
    清除搜索功能清空搜索参数 重新获取列表
  • 相关阅读:
    App安全架构之前端安全防护
    插入排序和归并排序
    【python中级】获得计算机的物理CPU核心数量
    调用MapReuce对文件中各单词出现次数统计
    xlsx实操
    【路径规划】基于FMM快速行进法实现船舶路径规划附matlab代码
    TinyOs操作系统---第4章 任务中断间的同步与通信
    go操作Mysql
    马赛克后挡板是什么?
    2023中国中医药展|中医理疗展|山东中医医疗器械展览会
  • 原文地址:https://blog.csdn.net/m0_54088431/article/details/126808705