• 作者:老汪软件技巧
  • 发表时间:2024-08-22 07:05
  • 浏览量:

useState 回调函数参数

用法: 能够给useState通过回调函数的形式给useState提供初始参数。

介绍:useState 的参数可以有两种形式:

1.  useState(普通的数据) => useState(0) / useState('abc')
2.  useState(回调函数) => useState(() => { return 初始值 })

在 useState(回调函数) 中,回调函数的返回值就是状态的初始值, 该回调函数只会触发一次。

使用 回调函数 来为 useState 初始化默认值

回调函数的返回值就是状态的初始值!

注意:该回调函数只会触发一次

  const [list, setList] = useState(() => {
    return JSON.parse(localStorage.getItem('comments')) || comments
  })

该使用哪种形式?

如果状态就是一个普通的数据(比如,字符串、数字、数组等)都可以直接使用 useState(普通的数据)如果状态是经过一些计算得到的,此时,推荐使用 useState(回调函数)第一种:

const [list, setList] = useState(
  JSON.parse(localStorage.getItem('list')) || arr
)

可以转化为:

这种情况下,只要组件更新,此处的 localStorage 等操作就会重复执行


 const initList = JSON.parse(localStorage.getItem('list')) || comments
 const [list, setList] = useState(initList)

第二种:

这种方式,因为回调函数只会执行一次,所以,此处的 localStorage 等操作代码只会执行一次

const [list, setList] = useState(() => {
  return JSON.parse(localStorage.getItem('comments')) || comments
})

所以在这种情况下,推荐使用第二种方式

useEffect清理副作用

用法: 能够在组件卸载的时候,清除注册的事件

介绍: useEffect 的返回值是可选的,可省略。也可以返回一个清理函数,用来执行事件解绑等清理操作。

清理函数的执行时机:

建议:一个 useEffect 只处理一个功能,有多个功能时,使用多次 useEffect

useEffect(() => {
  const handleResize = () => {}
  window.addEventListener('resize', handleResize)
  
  // 这个返回的函数,会在该组件卸载时来执行
  // 因此,可以去执行一些清理操作,比如,解绑 window 的事件、清理定时器 等
  return () => window.removeEventListener('resize', handleResize)
})

获取当前鼠标位置

案例: 能够实现让图片跟随鼠标移动

介绍:

import { useEffect, useState } from 'react'
import img from './1.gif'
export default function Move() {
  const [position, setPosition] = useState({
    x: 0,
    y: 0
  })
  useEffect(() => {
    const move = (e) => {
      console.log('开始运动')
      setPosition({
        x: e.pageX,
        y: e.pageY
      })
    }
    document.addEventListener('mousemove', move)
    console.log('触发注册事件')
    return function () {
      document.removeEventListener('mousemove', move)
    }
  }, [])
  return (
    <div>
      <img
        src={img}
        style={{
          position: 'absolute',
          top: position.y + 1,
          left: position.x + 1
        }}
        alt=""
      />
    div>
  )
}

自定义hooks

目标: 能够使用自定义hooks实现状态的逻辑复用

内容: 除了使用内置的 Hooks 之外,还可以创建自己的 Hooks(自定义 Hooks)。

useXxx 使用场景: 将组件状态逻辑提取到可重用的函数(自定义 Hooks)中,实现状态逻辑复用。

内置 Hooks 为函数组件赋予了 class 组件的功能;在此之上,自定义 Hooks 针对不同组件实现不同状态逻辑复用。

// 使用hooks实现猫跟着鼠标移动
import { useEffect, useState } from 'react'
export default function useMouse() {
  const [position, setPosition] = useState({
    x: 0,
    y: 0,
  })
  useEffect(() => {
    const move = (e) => {
      setPosition({
        x: e.pageX,
        y: e.pageY,
      })
    }
    document.addEventListener('mousemove', move)
    return () => {
      document.removeEventListener('mousemove', move)
    }
  }, [])
  return position
}

useEffect发送请求

目的: 能够在函数组件中通过useEffect发送ajax请求

内容: 在组件中,使用 useEffect Hook 发送请求获取数据(side effect):

_回调函数参数_回调函数参数传递

错误演示:

// 不要给 effect 添加 async
useEffect(async () => {
    const res = awiat xxx()
    return ()=> {
        
    }
}, [])

正确使用:

useEffect(() => {
  async function fetchMyAPI() {
    let url = 'http://something/' + productId
    let config = {}
    const response = await myFetch(url)
  }
  fetchMyAPI()
}, [productId])

useRef 操作DOM

目标: 能够使用useRef操作DOM

内容: 在 React 中进行 DOM 操作时,用来获取 DOM

作用:返回一个带有 current 属性的可变对象,通过该对象就可以进行 DOM 操作了。

const inputRef = useRef(null)

解释:

/* 
  1. 使用useRef能够创建一个ref对象,  有current属性  {current: null}
    const xxRef = useRef(null)
  
  2. 通过ref属性关联到某个DOM对象上  {current: DOM}
    
3. 可以通过 xxRef.current访问到对应的DOM */
const App = () => { const inputRef = useRef(null) const add = () => { console.log(inputRef.current.value) } return ( <section className="todoapp"> <input type="text" placeholder="请输入内容" ref={inputRef} />{' '} <button onClick={add}>添加button> section> ) } export default App

useContext-context

目标:实现跨级组件通讯

内容

useContext的用法useContext与的区别

1、 :在 JSX 标签内获取 Context 数据。

2、 useContext: 在 JavaScript 代码块中获取 Context 数据。

使用场景Context 的作用Context 对象包含的两个主要部分

Provider 组件

Consumer 组件

Consumer 组件行为有 Provider 时: 如果一个 Consumer 组件位于一个 Provider 的后代组件中,则它将获取到该 Provider 的value属性的值。无 Provider 时: 如果一个 Consumer 组件没有被任何 Provider 包裹,则它将获取到createContext创建时提供的defaultValue。示例

为了更好地理解如何使用 Context 和 useContext,下面是一个简单的示例:

import React, { createContext, useContext } from 'react';
// 创建 Context
const ThemeContext = createContext();
// Provider 组件
function ThemeProvider({ children }) {
  return (
    <ThemeContext.Provider value="dark">
      {children}
    ThemeContext.Provider>
  );
}
// 使用 useContext 的函数组件
function Navbar() {
  const theme = useContext(ThemeContext);
  return (
    <div>
      <h1>The current theme is: {theme}h1>
    div>
  );
}
// 主组件
function App() {
  return (
    <ThemeProvider>
      <Navbar />
    ThemeProvider>
  );
}
export default App;

Context 作用是实现跨组件传递数据,而不必在每个级别手动传递 props,简化组件之间的数据传递过程,那么使用Context 和不使用的区别在哪里呢 ?

不使用Context的情况(传统的Props Drilling)

父组件 (Parent Component)

中间组件 (Intermediate Component)

子组件 (Child Component)

这种情况下,数据必须从父组件层层传递到最底层的子组件,即使某些中间组件并不关心这些数据。这被称为“props drilling”。

描述


Parent Component
  |
  |--- Props
  |
  +-- Intermediate Component
        |
        |--- Props
        |
        +-- Child Component
              |
              |--- Uses Props

使用Context的情况

父组件 (Parent Component)

中间组件 (Intermediate Component)

子组件 (Child Component)

在这种情况下,数据通过Context Provider传递给整个组件树中的所有组件,不需要显式地在每一层都传递props。

描述


Parent Component
  |
  |--- Context Provider
  |
  +-- Intermediate Component
        |
        +-- Child Component
              |
              |--- useContext to access data

总结