react3-useEffect()、组件通信(props、context)、useContext()、useReducer()、useRef()、自定义钩子Custom Hooks、useId hook、useForm

useEffect()

允许执行一些副作用,如在组件中直接获取数据、更新DOM、打印某些内容等

语法:useEffect(() => {})


依赖数组

  • 提供数组(依赖数组),那么回调函数会在每次渲染时被调用

    import { useState, useEffect } from "react"
    
    const App = () => {
      const [value, setValue] = useState(0)
    
      // 会在每次重新渲染时允许这段代码
      useEffect(() => {
        console.log('useEffect')
        document.title = `Increment ${value}`
      })
    
      return <>
        <h2>{value}</h2>
        <button onClick={() => setValue(value+1)}>Increment</button>
      </>
    }
    
    export default App
    
  • 当指定一个空依赖数组时,使用useEffect时,只会在useEffect钩子中可用的函数上查找初始渲染,如组件的第一次渲染,而不是当组件更改时(只在初始时渲染一次

      useEffect(() => {
        console.log('useEffect')
        document.title = `Increment ${value}`
      }, [])
    
  • 如果数组中提供了某状态的值,每当该状态发生变化该组件将重新渲染并触发回调函数


使用场景

  • 若需监听所有更新(如实时计算),可省略依赖数组

  • 若只需初始化操作(如数据请求),应使用数组

  • 若需针对性监听某些状态变化,应在数组中指定依赖项


无依赖数组和有依赖项的区别

  • 副作用函数会在每次组件渲染后都执行(包括首次渲染和所有后续更新)

  • 相当于同时监听了组件的挂载和所有可能的更新

  • 可能导致性能问题,因为执行频率过高


条件渲染

不允许在条件渲染内部包裹useEffect钩子

useEffect(以及所有 React Hooks)必须在组件的顶层作用域中调用,不能放在条件语句、循环或嵌套函数内部

原因:可能导致某些渲染中 Hook 被跳过,使得React 无法正确关联 Hook 与对应的状态

import { useState, useEffect } from "react"

const App = () => {
  const [data, setData] = useState([])

  useEffect(() => {
    async function getData() {
      const res = await fetch('https://jsonplaceholder.typicode.com/todos')
      const dataRes = await res.json() // 一定要用await
      if (dataRes && dataRes.length){     
         setData(dataRes)
      }
    }

    getData()
    
  }, [])

  return <>
    <ul>
      {
        data.map((item) => {
          return <li key={item.userId}> {item.title} </li>
        })
      }
    </ul>
  </>
}

export default App

wechat_2025-08-26_111457_641


数据传递

prop drilling(属性钻取)

通过props父子组件通信来传递数据

企业微信截图_20250826142144

父组件:

import ComponentA from "./components/ComponentA"

const App = () => {
  const name = 'yuanyu'

  return <>
    <ComponentA name={name}/>
  </>
}

export default App

子组件1:

import ComponentB from './ComponentB'

const ComponentA = ({name}) => {
  return (
    <div>
      <ComponentB name={name}/>
    </div>
  )
}

export default ComponentA

子组件2:

import ComponentC from './ComponentC'

const ComponentB = ({name}) => {
  return (
    <div>
      <ComponentC name={name}/>
    </div>
  )
}

export default ComponentB

子组件3:

const ComponentC = ({name}) => {
  return (
    <div>
      <h1>{name}</h1>
    </div>
  )
}

export default ComponentC

企业微信截图_20250826141450


context API

允许在组件树中管理共享状态,无需手动在每个级别上传递props

步骤:

  1. 在父组件中引用createContextimport { createContext } from "react"

  2. 创建createContext实例:export const Data = createContext()

  3. 包裹子组件并通过示例.Provider提供数据:

    <Data.Provider value={name}>
      <子组件/>
    </Data.Provider>
    
  4. 子组件中通过实例.Consumer+回调函数接收数据:

    import { Data } from "../App"
    

传递一个数据

父组件:

import ComponentA from "./components/ComponentA"
import { createContext } from "react"

export const Data = createContext() // 创建createContext实例

const App = () => {
  const name = 'yuanyu'

  return <>
    <Data.Provider value={name}>
      <ComponentA/>
    </Data.Provider>
  </>
}

export default App

子组件1:

import ComponentB from './ComponentB'

const ComponentA = () => {
  return (
    <div>
      <ComponentB/>
    </div>
  )
}

export default ComponentA

子组件2:

import ComponentC from './ComponentC'

const ComponentB = () => {
  return (
    <div>
      <ComponentC/>
    </div>
  )
}

export default ComponentB

子组件3:

import { Data } from "../App"

const ComponentC = () => {
  return (
    <Data.Consumer>
      {
        (name) => {
          return <h1>{name}</h1>
        }
      }
    </Data.Consumer>
  )
}

export default ComponentC

传递两个数据

父组件:

import ComponentA from "./components/ComponentA"
import { createContext } from "react"

export const Data = createContext() // 创建createContext实例
export const Data1 = createContext()

const App = () => {
  const name = 'yuanyu'
  const age = 24

  return <>
    <Data.Provider value={name}>
      <Data1.Provider value={age}>
        <ComponentA />
      </Data1.Provider>

    </Data.Provider>
  </>
}

export default App

孙组件:

import { Data, Data1 } from "../App"

const ComponentC = () => {
  return (
    <Data.Consumer>
      {
        (name) => {
          return (
            <Data1.Consumer>
              {
                (age) => {
                  return (
                    <h1>My name is {name}, my age is {age}</h1>
                  )
                }
              }
            </Data1.Consumer>
          )
        }
      }
    </Data.Consumer>
  )
}

export default ComponentC

传递多个数据

将多个属性写入一个对象中进行传递

父组件:

import ComponentA from "./components/ComponentA"
import { createContext } from "react"

export const Data = createContext() // 创建createContext实例
export const Data1 = createContext()

const App = () => {
  const name = 'yuanyu'
  const age = 24
  const user = {
    name,
    age
  }

  return <>
    <Data.Provider value={user}>
        <ComponentA />
    </Data.Provider>
  </>
}

export default App

孙组件:

import { Data } from "../App"

const ComponentC = () => {
  return (
    <Data.Consumer>
      {
        (user) => {
          return <h1>
            My name is {user.name}, age is {user.age}.
          </h1>
        }
      }
    </Data.Consumer>
  )
}

export default ComponentC

useContext()

允许在函数中直接访问由context对象提供的context值

步骤:

  1. 在父组件中通过createContext提供值

  2. 在子组件中引入useContext()钩子:import { useContext } from "react"

  3. 获取context的值: const userName = useContext(Data)

  4. 在子组件中使用

父组件:

import ComponentA from "./components/ComponentA"
import { createContext } from "react"

export const Data = createContext() // 创建createContext实例
export const Data1 = createContext()

const App = () => {
  const name = 'yuanyu'
  const age = 24

  return <>
    <Data.Provider value={name}>
      <Data1.Provider value={age}>
        <ComponentA/>
      </Data1.Provider>   
    </Data.Provider>
  </>
}

export default App

孙组件:

import { Data, Data1 } from "../App"
import { useContext } from "react"

const ComponentC = () => {
  const userName = useContext(Data)
  const userAge = useContext(Data1)
  
  return (
    <h1>My name is {userName}, my age is {userAge}</h1>
  )
}

export default ComponentC

zustand

redux toolkit


useReducer()

与useState()相似,但是为更复杂的状态对象或状态过渡设计的,涉及多个子值,允许以功能和不变的方法管理

语法:const [state,dispatch] = useReducer(reducer, initialState)

  • initialState:初始值
  • reducer:一个函数,用于执行某些操作并返回新的状态,接收stateaction两个参数
  • state:当前状态
  • dispatch:调用操作来发送到reducer的函数并更新状态

例1:

import { useReducer } from "react"

const App = () => {
  const initialState = {count: 0}

  const reducer = (state, action) => {
    switch (action.type) {
      case 'increment':
        return {...state, count: state.count + 1}
      case 'decrement':
        return {...state, count: state.count - 1}
      case 'reset':
        return {...state, count: 0}
    }
  }
  const [state,dispatch] = useReducer(reducer, initialState)

  return <>
    <button onClick={() => dispatch({type: 'increment'})}>+</button>
    <button onClick={() => dispatch({type: 'decrement'})}>-</button>
    <button onClick={() => dispatch({type: 'reset'})}>reset</button>
    <h1>count: {state.count}</h1>
  </>
}

export default App

例2:

const initialState = {count: 0}

function counterReducer(state, action) {
    switch (action.type) {
        case 'increment':
            return {...state, count: state.count + 1}
        case 'decrement':
            return {...state, count: state.count - 1}
        case 'incrementByAmount':
            return {...state, count: state.count + action.amount} 
        case 'decrementByAmount':
            return {...state, count: state.count - action.amount}
        default:
            return state
    }
}

export {initialState, counterReducer}
import {initialState, counterReducer} from './counterReducer'
import { useReducer, useState } from 'react'

const Counter = () => {
    const [state, dispatch] = useReducer(counterReducer, initialState)
    const [inputValue, setInputValue] = useState(0)

    return (
        <div>
            <h1>count: {state.count}</h1>
            <button onClick={() => dispatch({type: 'increment'})}>+</button>
            <button onClick={() => dispatch({type: 'decrement'})}>-</button>
            <input type="number" value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
            <button onClick={() => dispatch({type: 'incrementByAmount', amount: +inputValue})}>Add</button>
            <button onClick={() => dispatch({type: 'decrementByAmount', amount: +inputValue})}>Substract</button>
        </div>
    )
}

export default Counter
import Counter from './components/Counter'

const App = () => {
  return <>
    <Counter/>
  </>
}

export default App

企业微信截图_20250826160139


useRef()

访问、与DOM元素交互的方式

import { useRef } from "react"

const App = () => {
  const element = useRef(null)
  console.log(element) // current: null
  return <></>
}

export default App

current属性允许操作DOM或对DOM做一系列操作

例:

import { useRef } from "react"

const App = () => {
  const element = useRef(null)
  console.log(element) // current: null

  const focusInput = () => {
    element.current.focus() //通过current属性操作DOM
    element.current.value = 'yuanyu'
  }
  return <>
    <input type="text" ref={element}/>
    <button onClick={() => focusInput()}>focus & write</button>
  </>
}

export default App

企业微信截图_20250826163433


Custom Hooks

自定义钩子是JS函数以use开头,可以复用简化代码

例:

import { useState, useEffect } from 'react'

const useFetch = (url) => {
    const [data, setData] = useState(null)
    
    useEffect(() => {
        fetch(url).then((res) => {
            res.json()
        }).then((data) => setData(data))
    }, [url])
    
    return [data]
}

export default useFetch

useId hook

在react中用于为组件生成唯一的id

例:

import { useId } from "react"

const UniqueId = () => {
    const id = useId()
  return (
    <div>
      <label htmlFor={id}>Email</label>
      <input type="email" id={id} />
    </div>
  )
}

export default UniqueId

企业微信截图_20250826164911

例:

import { useId } from "react"

const UniqueId = () => {
    const id = useId()
  return (
    <div>
      <label htmlFor={`${id}-email`}>Email</label>
      <input type="email" id={`${id}-email`} />

      <label htmlFor={`${id}-password`}>Password</label>
      <input type="password" id={`${id}-password`} />
    </div>
  )
}

export default UniqueId

企业微信截图_20250826165249


useForm

网址 :Get Started

  • 安装:npm i react-hook-form
  • 使用:const {register, handleSubmit, formState: {errors, isSubmitting}} = useForm()
    • register:用于将输入字段连接到表单
    • handleSubmit:表单提交处理函数
    • errors:表单的验证错误
import { useForm } from 'react-hook-form'

interface FormData {
    name: string
    email: string
    password: string
}

const Form = () => {

    const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<FormData>()

    const onSubmit: handleSubmit<FormData> = (data) => {
        console.log(data)
    }
    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <div className="name">
                <label htmlFor="name">Name:</label>
                <input type="text" id='name' {...register("name", { required: 'Name is required.' })} />
                {errors.name && <p style={{ color: 'red' }}>{errors.name.message}</p>}
            </div>
            <div className="email">
                <label htmlFor="email">Email:</label>
                <input type="email" id='email' {...register("email", {
                    required: 'Email is required.',
                    pattern: {
                        value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
                        message: 'Invalid email address.'
                    }
                })} />
                {errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
            </div>
            <div className="password">
                <label htmlFor="password">Password:</label>
                <input type="password" id='password' {...register("password", { required: 'Password is required.' })} />
                {errors.password && <p style={{ color: 'red' }}>{errors.password.message}</p>}
            </div>
            <button type='submit' disabled={isSubmitting}>Submit</button>
        </form>
    )
}

export default Form

wechat_2025-09-02_095144_654

wechat_2025-09-02_095241_193

posted @ 2025-08-26 16:59  原语  阅读(7)  评论(0)    收藏  举报