学习react 笔记五 (useEffect、useRef、useContext)

目录

一、useEffect副作用

 (1)使用useEffect

(2)执行时机(第二个参数)

(3)倒计时demo

(4)请求ajax

(5)useEffect的清理函数

(6)图片移动demo

(7)图片移动demo 封装

二、 useRef(引用)

(1)使用方法

(2)demo 获取input的值

(3)demo 清除定时器

(4)demo 验证码倒计时

(5)demo 验证码倒计时 抽离hooks

三、useContext(跨组件传值)

一、使用方法

二、传值Demo


一、useEffect副作用

 副作用: 平常把一些 除了定义 和 dom 一些无关的代码放到effect里,(例如请求ajax)

 (1)使用useEffect

import {  useEffect } from 'react'
 useEffect(() => {
    console.log('useEffect1')
  })

(2)执行时机(第二个参数)

 情况一:不写第二个参数,页面创建 和 数据更新会执行 

 useEffect(() => {
    console.log('useEffect1')
  })

情况二:第二个参数是空数组  执行时机: 只有在组件创建时会执行一次

 useEffect(() => {
    console.log('useEffect2')
  }, [])

情况三:第二个参数 依赖项  执行时机:页面创建 和依赖数据更新了 会执行  注意写法是  [ 变量 ]

 useEffect(() => {
    console.log('useEffect3')
  }, [a])

(3)倒计时demo

import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom/client'

const Ren = function () {

  const [a, setA] = useState(100)

  useEffect(() => {
    setInterval(() => {
      console.log('倒计时', a)
      setA(e => e - 1)
    }, 1000)
  }, [])


  return <div>倒计时100个数 {a} </div >
}

(4)请求ajax

import React, { useEffect, useState } from 'react'
import ReactDOM from 'react-dom/client'
import axios from 'axios'
const Ren = function () {

  useEffect(() => {
    axios({
      method: 'GET',
      url: 'https://www.xxx.cn/api/cart',
      data: {}
    }).then(res => {
      console.log(res)
    })
  })
  return <div></div>
}

写成 async await形式 

错误写法:

  useEffect(async () => {
    await axios({
      method: 'GET',
      url: 'https://www.xxx.cn/api/cart',
      data: {}
    }).then(res => {
      console.log(res)
    })
  })

正确写法:

  useEffect(() => {
    const getList = async () => {
      const res = await axios({
        method: 'GET',
        url: 'https://www.xxx.cn/api/cart',
        data: {}
      })
      console.log(res)
    }
    getList()
  })

async 后面要跟一个promise 而useEffect并不是 所以 我们可以在useEffect里定义一个函数 直接调用

(5)useEffect的清理函数

副作用函数的返回值是可选的,也可以省略,也可以返回一个清理函数 清理副作用

执行时机:清理函数会在 组件卸载时以及下次副作用函数调用之前执行

useEffect(() => {
    return () =>  // 做清理工作
  })

demo 清除鼠标移动事件

import React, { useEffect, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'
const Ren = function () {
  useEffect(() => {
    const f = (e) => {
      console.log(e.screenX, e.screenY)
    }
    window.addEventListener('mousemove', f)
    return () => {
      window.removeEventListener('mousemove', f)
    }
  })
  return <h1>111</h1>
}

export default function Use () {
  const [isShow, toggle] = useState(true)
  const hide = () => {
    toggle(false)
  }
  return (
    <div>
      {isShow && <Ren></Ren>}
      <div onClick={hide}>切换</div>

    </div>
  )
}

// const root = ReactDOM.createRoot(document.getElementById('root'))
// root.render(<Use />)

ReactDOM.render(<Use></Use>, document.getElementById('root'))

在上面代码中 在组件里绑定了鼠标事件 当销毁组件时 事件并不会被销毁 这时候可以利用useEffect清理函数来清除掉 鼠标移动事件

(6)图片移动demo

import React, { useEffect, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'
import img from '../images/avatar.png'

const Ren = function () {
  const [X, setX] = useState(0)
  const [Y, setY] = useState(0)

  useEffect(() => {
    const f = (e) => {
      console.log(e.screenX, e.screenY)
      setX(() => e.screenX)
      setY(() => e.screenY)
    }
    window.addEventListener('mousemove', f)
    return () => {
      window.removeEventListener('mousemove', f)
    }
  })
  return (
    <div style={{ width: "50px", height: "50px" }}>
      <img src={img} style={{ width: "50px", height: "50px", position: "absolute", left: X + 'px', top: Y + 'px' }}></img>
    </div>
  )
}

// const root = ReactDOM.createRoot(document.getElementById('root'))
// root.render(<Use />)

ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

(7)图片移动demo 封装

mouseMoveXY.js

import React, { useEffect, useState } from 'react'

// 如果是函数组件首字母要大写 如果是hooks函数 要以use开头 
// 调用要在 函数组件里面调用 
export default function useMouseMove () {
  const [X, setX] = useState(0)
  const [Y, setY] = useState(0)

  useEffect(() => {
    const f = (e) => {
      console.log(e.screenX, e.screenY)
      setX(() => e.screenX)
      setY(() => e.screenY)
    }
    window.addEventListener('mousemove', f)
    return () => {
      window.removeEventListener('mousemove', f)
    }
  })
  return { X, Y }
}

使用

import React, { useEffect, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'
import img from '../images/avatar.png'
import mousemove from './mouseMoveXY'
const Ren = function () {
  const { X, Y } = mousemove()
  return (
    <div style={{ width: "50px", height: "50px" }}>
      <img src={img} style={{ width: "50px", height: "50px", position: "absolute", left: X + 'px', top: Y + 'px' }}></img>
    </div>
  )
}

ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

二、 useRef(引用)

(1)使用方法

1.导入 import React, { useRef } from 'react'

2.定义 const getInput = useRef(null)

3.使用  ref={getInput}

(2)demo 获取input的值

import React, { useRef, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'
const Ren = function () {
  const getInput = useRef(null)
  console.log(getInput)
  const [text, SetText] = useState('')
  const edit = (e) => {
    console.log(e.target.value)
    SetText(() => e.target.value)
  }
  const getText = () => {
    console.log(getInput.current.value)
  }
  return (
    <div>
      <input value={text} onChange={edit} ref={getInput}></input>
      <button onClick={getText}>获取input的值</button>
    </div>
  )
}


ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

(3)demo 清除定时器

import React, { useEffect, useRef, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'
const Ren = function () {
  const getInput = useRef(null)
  console.log(getInput)
  const timer = useRef(null)
  const [Num, setNum] = useState(0)
  // let timer = null  //相当于每次都是在赋值一个null 错误写法
  useEffect(() => {
    // timer = setInterval(() => {
    timer.current = setInterval(() => {
      setNum(() => Num + 1)
    }, 1000)
  }, [])
  const edit = (e) => {

  }
  const clearTimer = () => {
    // clearInterval(timer)
    clearInterval(timer.current)
  }
  return (
    <div>
      <div>倒计时 {Num} </div>
      <button onClick={clearTimer}>清除定时器</button>
    </div>
  )
}


ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

如果在外层定义一个timer 定义定时器 当每次倒计时 值发生改变时 整个组件都会重新执行 相当于每次倒计时都在定义了一个timer 如果想清除定时器 可以 用useRef  把定义的变量 使用  变量.current 来当成定时器 的变量  可以理解为 useRef 定义的 current里永远都是引用类型 不会改变

(4)demo 验证码倒计时

import React, { useEffect, useRef, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'

const Ren = function () {
  const timer = useRef(null)
  const [Num, setNum] = useState(3)
  const [Status, setStatus] = useState(false)

  const countDown = () => {
    timer.current = setInterval(() => {
      setNum((Num) => {
        setStatus(true)
        return Num - 1
      })
    }, 1000)
  }

  useEffect(() => {
    if (Num == 0) {
      clearInterval(timer.current)
      setStatus(false)
      setNum(3)
    }
    console.log(Num)
  }, [Num])
  return (
    <div>
      <div>倒计时 {Num} </div>
      <button disabled={Status} onClick={countDown}>{Status ? Num + '秒后重新获取' : '获取验证码'}</button>
    </div>
  )
}


ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

(5)demo 验证码倒计时 抽离hooks

import React, { useEffect, useRef, useState } from 'react'
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom'
const useCount = (count = 10, callback = () => { }) => {
  const timer = useRef(null)
  const [Num, setNum] = useState(null)

  const start = () => {
    setNum(count)
    timer.current = setInterval(() => {
      setNum(num => num - 1)
    }, 1000)
  }

  useEffect(() => {
    if (Num == 0) {
      clearInterval(timer.current)
      callback()
    }
  }, [Num])


  return { start, Num }
}

const Ren = function () {

  const [Status, setStatus] = useState(false)
  const { start, Num } = useCount(3, () => {
    setStatus(false)
  })
  const countDown = () => {
    setStatus(true)
    start()
  }

  return (
    <div>
      <div>倒计时 {Num} </div>
      <button disabled={Status} onClick={countDown}>获取验证码</button>
    </div>
  )
}


ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

count 作为倒计时秒数、callback作为 倒计时之后的回调函数 

demo 验证码倒计时封装抽离出一个组件 useCountDown.js

import { useEffect, useRef, useState } from 'react'
export default function useCountDown (count = 10, callback = () => { }) {
  const timer = useRef(null)
  const [Num, setNum] = useState(null)

  const start = () => {
    setNum(count)
    timer.current = setInterval(() => {
      //组件清楚后仍会执行
      console.log(1)
      setNum(num => num - 1)
    }, 1000)
  }

  useEffect(() => {
    if (Num == 0) {
      setNum(count)
      clearInterval(timer.current)
      callback()
    }
  }, [Num])

  useEffect(() => {
    return () => {
      clearInterval(timer.current)
    }
  }, [])


  return { start, Num }
}

记得通过useEffect的清理函数 清理一下 定时器事件 极端情况下 销毁组件后 延时器仍会执行  

使用

import React, { useState } from 'react'
import ReactDOM from 'react-dom'

import useCountDown from './useCountDown'

const Ren = function () {

  const [Status, setStatus] = useState(false)
  const { start, Num } = useCountDown(3, () => {
    setStatus(false)
  })

  const countDown = () => {
    setStatus(true)
    start()
  }

  return (
    <div>
      <div>倒计时 {Num} </div>
      <button disabled={Status} onClick={countDown}>获取验证码</button>
    </div>
  )
}

ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

三、useContext(跨组件传值)

一、使用方法

1.导如并调用createContext 得到 Context对象 导出

import React, { useState, createContext } from 'react'
export const Context = createContext()

2.使用Provider包裹根组件 通过value属性提供共享数据

 return (
    <Context.Provider value={{ a: 1, b: 2 }}>
      <根组件内容/>
    </Context.Provider>
  )

3. 子代组件接收

import { useContext } from 'react'
 const value = useContext(Context)
 console.log(value)

二、传值Demo

 index.js 根组件

import React, {  createContext } from 'react'
import ReactDOM from 'react-dom'


import Father from './father'
export const Context = createContext()
const Ren = function () {

  return (
    <Context.Provider value={{ a: 1, b: 2 }}>
      <div>
        <div>根组件</div>
        <div style={{ border: '1px solid #ccc' }}> <Father /></div>
      </div>
    </Context.Provider>
  )
}


ReactDOM.render(<Ren></Ren>, document.getElementById('root'))

father.js 父组件

import Son from './son.js'
function Father () {

  return (
    <div>
      <div>父组件</div>
      <div style={{ border: '1px solid #ccc' }}> <Son /></div>
    </div>
  )
}

export default Father

son.js 子组件

import { Context } from './index'
import { useContext } from 'react'
function Son1 () {
  const value = useContext(Context)
  return (
    <div>
      <div> 孙子组件: {value.a} {value.b} </div>
    </div>
  )
}

export default Son1

 

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]:在React中,memo是一个高阶组件,用于优化函数组件的性能。它类似于React.PureComponent,通过对内部对象进行浅比较来判断是否重新渲染组件。\[2\]useEffectReact提供的一个Hook函数,用于在函数组件中执行副作用操作。它可以在组件渲染完成后执行一些异步操作,比如发送网络请求、订阅事件等。\[3\]useMemo是React提供的另一个Hook函数,用于在函数组件中进行性能优化。它可以缓存计算结果,避免重复计算,类似于Vue中的computed属性。\[1\]useRefReact提供的一个Hook函数,用于在函数组件中创建一个可变的引用。它可以用来保存组件的状态,或者获取DOM元素的引用。\[1\]useState是React提供的一个Hook函数,用于在函数组件中创建一个可变的状态。它返回一个数组,第一个元素是当前的状态值,第二个元素是更新状态的函数。 所以,react memo用于优化函数组件的性能,useEffect用于执行副作用操作,useMemo用于缓存计算结果,useRef用于创建可变的引用,useState用于创建可变的状态。 #### 引用[.reference_title] - *1* *2* [useMemo,memo,useRef等相关hooks详解](https://blog.csdn.net/weixin_44441196/article/details/117328033)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [一文轻松掌握react-hook(useState、useReducer、useEffectuseCallback、useMemo、useRefuseContext...)](https://blog.csdn.net/u010074572/article/details/105176653)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值