React hooks API详情

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

hook 是react 16.8的新增特性 ,他可以让你不在编写class的情况下shiystate以及react的特性
Hooks的出现,首先解决了以下问题:
  1. 告别了令人疑惑的生命周期
  2. 告别类组件中烦人的this
  3. 告别繁重的类组件,回归到了熟悉的函数组件
react 整个思想上面的转变,从“面向对象”的思想转为“函数式编程”,所以你会突然发现会多了一些新概念 比如:纯函数,副作用,柯里化,高阶函数等概念
 

useState 

 

 1.基础使用

import { useState } from 'react'
function App() {
    // 参数:状态初始值比如,传入 0 表示该状态的初始值为 0
    // 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)
    const [count, setCount] = useState(0);
    //   修改count内容
    const modifyEvent = () => {
        setCount(count + 1)
    }
    return (
        <button onClick={() => modifyEvent()}>{count}</button>
    )
}
export default App

 

 2.状态的读取和修改执行流程与逻辑

  读取状态:该方式提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用
  修改状态:

    1.setCount是一个函数,参数表示最新的状态值

    2.调用该函数后,将使用新值替换旧值

    3.修改状态后,由于状态发生变化,会引起试图变化 注意

  事项:修改状态的时候,一定要使用新的状态替换旧的状态,不能直接修改旧的状态,尤其是引用类型

 

3. 组件的更新过程

  函数组件使用 useState hook 后的执行过程,以及状态值的变化

  1.组件第一次渲染

  • 从头开始执行该组件中的代码逻辑
  • 调用 useState(0) 将传入的参数作为状态初始值,即:0
  • 渲染组件,此时,获取到的状态 count 值为: 0

  2.组件第二次渲染

  • 点击按钮,调用 setCount(count + 1) 修改状态,因为状态发生改变,所以,该组件会重新渲染
  • 组件重新渲染时,会再次执行该组件中的代码逻辑
  • 再次调用 useState(0) ,此时 React 内部会拿到最新的状态值而非初始值,比如,该案例中最新的状态值为 1
  • 再次渲染组件,此时,获取到的状态 count 值为:1
注:useState 的初始值(参数)只会在组件第一次渲染时生效。也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件会记住每次最新的状态值 
import { useState } from 'react'
 
function App() {
  const [count, setCount] = useState(0)
  // 在这里可以进行打印
  console.log(count,'渲染了')
  return (
    <button onClick={() => { setCount(count + 1) }}>{count}</button>
  )
}
export default App

 4.使用规则

  1.useState 函数可以执行多次,每次执行互相独立,每调用一次为函数组件提供一个状态
function List(){
  // 以字符串为初始值
  const [name, setName] = useState('cp')
  // 以数组为初始值
  const [list,setList] = useState([])
}

  2.useState 注意事项

  • 只能出现在函数组件或者其他hook函数中
  • 能嵌套在if/for/其它函数中(react按照hooks的调用顺序识别每一个hook)

 

useEffect

1.理解函数副作用

   副作用是相对于主作用来说的,一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用(比如,手动修改 DOM)
  常见的副作用:
  • 数据请求 ajax发送
  • 手动修改dom
  • localstorage操作
  useEffect函数的作用就是为react函数组件提供副作用处理的数据和逻辑,从而修改UI和用户交互等一种方式。
 

2. 基础使用

下面案例说明,函数组件储存了当前state所有状态,函数初次就会触发他们两个的加载,另外当某一个发生改变了 useEffect和函数都会被重新执行加载

import { useEffect, useState } from 'react'
 
function App() {
  const [count, setCount] = useState(0)
 
  useEffect(()=>{
    // 修改了dom数据后 userffect函数被副作用重新执行
    console.log('执行了副作用函数')
  });
    // 函数组件也会被重新执行   
  console.log('函数组件被重新执行了')
  return (
    <button onClick={() => { setCount(count + 1) }}>{count}</button>
  )
}
 
export default App

 

3.useEffect依赖项和控制执行的时机

由于 组件首次渲染执行一次,以及不管是哪个状态更改引起组件更新时都会重新执行
 
添加空数组依赖
import { useEffect, useState } from 'react'
function App() {
  const [count, setCount] = useState(0)
  useEffect(()=>{
    // 修改了dom数据后 userffect函数不会在被触发,只有首次加载函数才会执行一次
    console.log('执行了副作用函数')
  },[]);
    //修改了dom数据后 函数组件会被重新执行   
  console.log('函数组件被重新执行了')
  return (
    <button onClick={() => { setCount(count + 1) }}>{count}</button>
  )
}
export default App

添加特定项作为依赖

副作用函数在首次渲染时执行,在依赖项发生变化时重新执行

给useEffect添加特定的依赖项,当这个依赖性的state发生改变,useEffect与函数组件都会重新渲染被执行,由于第二个参数是依赖项所以是数组可以添加多个依赖项

没有useEffect添加的特定的依赖项,就不会触发useEffect函数,只会触发组件的渲染函数

function App() {  
    const [count, setCount] = useState(0)  
    const [name, setName] = useState('zs') 
    
    useEffect(() => {    
        console.log('副作用执行了')  
    }, [count])  
    console.log('组件被执行了')
    return (    
        <>      
         <button onClick={() => { setCount(count + 1) }}>{count}</button>      
         <button onClick={() => { setName('cp') }}>{name}</button>    
        </>  
    )
}

清理副作用

 
function App() {
    const [count, setCount] = useState(0)
    const [name, setName] = useState('zs')

    useEffect(() => {
        console.log('副作用执行了')
        return () => {
            alert(1)
            console.log('执行了清楚副作用,组件卸载的时候执行')
        }
    }, [count])
    console.log('组件被执行了')
    return (
        <>
            <button onClick={() => { setCount(count + 1) }}>{count}</button>
            <button onClick={() => { setName('cp') }}>{name}</button>
        </>
    )
}

 

另外一般一个 useEffect 只用来处理一个功能,有多个功能时,建议使用多个 useEffect
 

useMemo(性能优化)

解决函数组件的性能问题,比如子组件重复执行问题,每次渲染都进行高开销的计算

// 子组件
function Sub(props) {
    console.log("Sub render");
    let { number, onClick } = props
    return (
        <button onClick={onClick}>{number}</button>
    )
}
// 父组件
function Test() {
    let [value, setValue] = useState('')
    let [number, setNumber] = useState(0)
    const addClick = () => setNumber(number + 1)
    return <>
        <input type="text" value={value} onChange={(e) => setValue(e.target.value)} />
        <Sub number={number} onClick={addClick} />
    </>
}

export default Test;

子组件依赖的只有number ,理想情况下只希望number变化时触发子组件重新渲染

但实际是在输入框内的值发生变化,子组件也会重新渲染 如果子组件的逻辑较复杂,就是无意义的大量计算,浪费资源

// 子组件
function Sub(props) {
    console.log("Sub render");
    let { number, onClick } = props
    return (
        <button onClick={onClick}>{number}</button>
    )
}
// 父组件
function Test() {
    let [value, setValue] = useState('')
    let [number, setNumber] = useState(0)
    const addClick = () => setNumber(number + 1);
    // 使用useMemo记住计算后的值,只有当依赖number变量发生变化,才会重新计算子组件内容
    const MemoSub = useMemo(
        () => <Sub data={number} onClick={addClick} />,
        [number] // 只有 number 变化才重新计算 MenoSub
      )
    return <>
        <input type="text" value={value} onChange={(e) => setValue(e.target.value)} />
        {MemoSub}
    </>
}

export default Test;

 

useCallback(性能优化)

接收两个参数:回调函数和依赖项数组。回调函数是需要缓存的函数,依赖项数组用于确定何时需要重新创建函数实例。

当依赖项数组中的任何一个值发生变化时,useCallback 将返回一个新的函数实例,否则它将返回之前缓存的函数实例

import { useState, useCallback } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  // 使用 useCallback 缓存 handleClick 函数
  const handleClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      {/* 在按钮上使用缓存的 handleClick 函数 */}
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

在这个例子中,我们使用 useCallback 来缓存回调函数 handleClick, 将其缓存以避免在每次重新渲染组件时创建新的函数实例。

同时,在按钮上使用了缓存的 handleClick 函数,以确保点击按钮时调用的是缓存的函数实例。我们还将 count 添加到依赖项数组中,以确保每当 count 发生变化时,handleClick 都会被重新创建。

useCallback 和 useMomeo 的区别

1.useCallback 和 useMemo 都是用于性能优化的 React 钩子函数,它们都可以避免不必要的重新计算或重新渲染。虽然它们看起来很相似,但它们有几个重要的区别。

2.首先,useCallback 返回一个缓存的回调函数,而 useMemo 返回一个缓存的值。这意味着 useCallback 的主要作用是为一个函数创建缓存,而 useMemo 的主要作用是缓存一个值

3.最后,它们的使用场景也不同。useCallback 适用于优化回调函数,避免不必要的重新渲染,并传递给子组件。而 useMemo 适用于优化计算开销较大的值,如大型数组或对象的计算

 

useRef

useRef 可以缓存所有数据类型,更新的数据不会随着组件的重新渲染而重置,会一直保持最新状态的内容,

但是保存的数据类型 无法在ui渲染页面上使用,只能作为一个状态进行储存

也可以绑定给一个元素标签获取dom进行操作

function Test() {
    /* 保存 DOM */
    const inputEl = useRef()
    const onClick = () => {
        console.log(inputEl); // 对象类型,只有一个 current 属性指向指定DOM
        inputEl.current.innerHTML = '2asdasd sd阿萨德'
    }

    return <div>
        <div ref={inputEl}></div>
        <button onClick={onClick}>click me!!!</button>
        <br />
    </div>
}

 

useContext

usecontext React 16.3本中新引入的一个特性,它可以让组件之间共享数据十分方便。它属于 React Context API(上下文API),可以让组件层级之间自由传递数据,而使用Context API可以极大地提高组件之间的可复用性。
使用 useContext以使组件树中的任何组件访问到 cntext值,无论它是何种层级的,而且更方便的是,不需要利用props行传递,而只需要一行代码即可

下面案例是同一组件下多个 子组件的上下文通讯

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('light')
// 父组件
function Test() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar theme="dark" />
    </ThemeContext.Provider>
  )
}
// 子组件
function Toolbar(props) {
  return (
    // 中间的组件再也不必指明往下传递 theme 了。
    <div>
      <Button />
    </div>
  )
}
// 子组件中的子组件
function Button() {
  // 指定 contextType 读取当前的 themecontext。
  // React 会往上找到最近的 theme Provider,然后使用它的值。
  // 在这个例子中,当前的 theme 值为 “dark”。
  const theme = useContext(ThemeContext)
  return <button>{ theme }</button>
}

 

垮文件使用usecontext 进行通讯

 父组件

import React, { useState, createContext } from 'react'
import Counter from './Counter'
 
export const countContext = createContext()
 
export default function Example4() {
    const [count, setCount] = useState(0)
    return (
        <div>
            <p>你点击了{count}次</p>
            <button onClick={()=>{setCount(count+1)}}>点击</button>
            <countContext.Provider value={count}>
                <Counter />
            </countContext.Provider>
        </div>
    )
}

子组件

import React, { useContext } from 'react'
import { countContext } from './Example4'
 
function Counter() {
    let count = useContext(countContext)
    return (
        <div>
            <h2>{count}</h2>
        </div>
    )
}
 
export default Counter

 

 这样在多级组件使用就减少使用redux,useContext确实好用,起码跨级传递数据不用那么麻烦了

 

 完结,有不足欢迎补充。

 
 
posted on 2023-09-19 17:07  马丁的车夫  阅读(172)  评论(0编辑  收藏  举报