react训练通关之常用hook

146 阅读5分钟

1.state

  • setState(obj,callback)
    • 第一个参数:当 obj 为一个对象,则为即将合并的 state ;如果 obj 是一个函数
    • 那么当前组件的 state 和 props 将作为参数,返回值用于合并新的 state。
    • 第二个参数 callback :callback 为一个函数,函数执行上下文中可以获取当前 setState 更新后 的最新 state 的值,可以作为依赖 state 变化的副作用函数,可以用来做一些基于 DOM 的操作。

/* 第一个参数为function类型 */ 
this.setState((state,props)=>{ return { number:1 } }) 
/* 第一个参数为object类型 */ 
this.setState({ number:1 },()=>{ console.log(this.state.number) //获取最新的number })

2.useState

  1. state: 作为页面渲染的数据
  2. dispatch: 作为state的状态更新的函数
    1.如果为值,直接赋值给新的state作为渲染条件
    2.如果为函数,函数参数为当前state,新值为赋值给state的值 setState((state)=> state + 1)
  3. initData:
    1.可作为值进行传递,作为值传递的时为state默认值,
    2.作为函数进行传递时,函数返回值为state默认值
// [ state , setState ] = useState(initData)

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

3.useEffect

useEffect又称副作用hooks
作用:给没有生命周期的组件,添加结束渲染的信号。
执行时机:在渲染结束之后执行

  1. useEffect 第一个参数 callback, 返回的 destory , destory 作为下一次callback执行之前调用,用于清除上一次 callback 产生的副作用。
  2. 第二个参数作为依赖项,是一个数组,可以有多个依赖项,依赖项改变,执行上一次callback 返回的 destory ,和执行新的 effect 第一个参数 callback 。
  3. 在不接受第二个参数情况下,那么在第一次渲染完成之后和每次更新渲染页面的时候,都会调用useEffect的回调函数,
import React, { useEffect, useState } from 'react';

const DataFetcher = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    // 在组件挂载后执行副作用操作
    fetchData().then((result) => {
      setData(result);
    });

    // 在组件卸载前执行清理操作
    return () => {
      cleanup();
    };
  }, []);

  return <div>{data ? <p>Data: {data}</p> : <p>Loading...</p>}</div>;
};

4.useLayoutEffect

与useEffect对比

  • 相同点
    • 1.第一个参数,接收一个函数作为参数
    • 2.第二个参数,接收【依赖列表】,只有依赖更新时,才会执行函数
    • 3.返回一个函数,先执行返回函数,再执行参数函数
  • 不同点
    • 执行时机不同。useLayoutEffect在DOM更新之后执行;
    • useEffect在render渲染结束后执行。在测试代码中,useLayoutEffect执行永远在useEffect之前,这是因为DOM更新之后,渲染才结束或者渲染还会结束
import React, { useEffect, useState, useLayoutEffect } from 'react';

const DataFetcher = () => {
const [num, setNum] = useState(0)
//在类组件中用componentWillMount生命周期来实现
useLayoutEffect( () => {console.log('useLayoutEfffect')},[num])

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

return (
    <div onClick={ ()=>setNum( num => num+1 ) }> {num} </div>
)
};

5.useMemo

  • 1.接收一个函数作为参数
  • 2.同样接收第二个参数作为依赖列表(与useEffect、useLayoutEffect相似)
  • 3.返回的是一个值。返回值可以是任何,函数、对象等都可以
  • 4.使用场景有复杂计算逻辑优化、父子组件传值重新优化等;

对于复杂计算而言,使用useMemo包裹后,第一次计算后,会缓存的一个计算结果,只有在当依赖数组中的任何一个值发生变化时,计算函数将被重新计算,从而降低复杂计算带来的开销。例如在空依赖项的情况下,复杂计算只会在首次加载时执行。

import React, { useMemo } from 'react';

const = expensive => ({ value1, value2 }) {
  const result = useMemo(() => {
    console.log('calculating result');
       return value1 * value2;
  }, [value1, value2]);

  return <div>{result}</div>;
}

6.useCallback

与useMemo相似,useCallback也是一个对于状态优化的hook,它接受一个回调函数和一个依赖数组,并返回一个缓存的回调函数。当依赖数组中的任何一个值发生变化时,缓存的回调函数将被更新。

  • 不同点:
    • useCallback是缓存的是一个函数,对传过来的回调函数优化,返回的是一个函数;useMemo返回值可以是任何,函数,对象等都可以。
    • 复杂计算逻辑的场景不适合使用useCallback来缓存,因为传入的函数内容会不断执行。
  • 相同点:
    • useMemo与useCallback相同。接收一个函数作为参数,也同样接收第二个参数作为依赖列表
import React, { useState, useCallback } from 'react';

function Parent() {
  const [num, setNum] = useState(0);

  const handleClick = useCallback(() => {
    setNum(num + 1);
  }, [num]);

  return (
    <>
      <Child onClick={handleClick} />
      <span>{num}</span>
    </>
  );
}

function Child({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

7.useRef

注意:使用useRef的属性,不会主动触发页面重新渲染。

useRef 用于在函数组件中保存可变值的引用,所以我们可以用来存储可变值:比如有一个值需要在渲染过程中保留,但不会影响组件的 UI 或触发重新渲染,此时使用useRef 是一个不错的选择。

usestate不同,useRef 主要用于访问和操作 DOM 或存储不触发重新渲染的可变值。它返回一个带有 current 属性的可变对象。

如下示例:
将 inputRef 使用useRef 进行包裹,并将其传入input的 ref 属性中,,此时我们就可以获取到input的 DOM 节点。
单击单击按钮时,将执行 handleClick 函数,并调用 input的 DOM 节点inputRef ,并唤起inputRef.current.focus聚焦() 方法进行input组件的focus聚焦。

import React, { useRef } from 'react';

function Input() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>Focus input</button>
    </>
  );
}


8.useContext

useContext是让子组件之间共享父组件传入的状态的。

  • 需要引入useContext,createContext两个内容
  • 通过createContext创建一个context
  • Context.Provider来确定数据共享范围
  • 通过value来分发内容
  • 在子组件中,通过useContext(Context)来获取数据
import React, { createContext, useContext } from 'react';

const MyContext = createContext(null);

function Consumer1() {
  const name = useContext(MyContext);

  return (
    <div>
      <div>消费者1消费{name}</div>
    </div>
  )
}

function Consumer2() {
  const name = useContext(MyContext);

  return (
    <div>
      <div>消费者2消费{name}</div>
    </div>
  );
}

function App() {
const [name, setName] = useState('生产者')
  return (
    <MyContext.Provider value={name}>
      <Consumer1 />
      <Consumer2 />
    </MyContext.Provider>
  );
}

9.useReducer

useReducer是在react V16.8推出的钩子函数,作用是替代useState,与Redux功能类似,主要用于形成一个全局的状态管理的 hook,redux的reducer,useReducer 的思路和redux一样,不同点是在于useReducer 最终操作的对象是state。

如下图声明了一个store数据仓库,与reducer数据处理方法,并通过state,dispacthstate,dispacth进行数据的更新与获取

const store = {
    age:18,
    num:1
}	//	数据仓库

const reducer = (state, action) => {
    switch(action.type){
        case 'add':
            return {
                ...state,
                num: action.num+1
            }

        default:
            return {
                ...state
            }
    }
} //	管理者

function StateFunction () {
    const [state,dispacth] = state,dispacth(reducer,store)  //	①

    return (
        <div>
            <button onClick={ () => {
                dispacth({
                    type: 'add',
                    num: state.num
                })
            } }>
                增加num的值+1
            </button>
            <br></br>
            这是一个函数式组件——num:{  state.num }
        </div>
    )
}