React中的hooks

一.useState

  1. useState会帮助我们定义一个 state变量,useState 是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数式组件中退出后变量就会”消失”,而 state 中的变量会被 React 保留。
  2. useState接受唯一一个参数,在第一次组件被调用时使用来作为初始化值(也可以是一个回调函数)。(如果没有传递参数,那么初始化值为undefined)。
    const [state, setstate] = useState(() => { return 10; })
  3. useState返回值是一个数组,我们可以通过数组的解构,来完成赋值会非常方便;
    const [counter, setCounter] = useState(0);
    // 不会进行累加:
    setCount(count + 10);
    setCount(count + 10);
    // 会进行累加:
    setCount((prevCount) => prevCount + 10);
    setCount((prevCount) => prevCount + 10);
  4. 注意: 使用useSate定义变量时不能写在判断条件中;

二.useEffect

1. 代替生命周期函数
componentDidMount / componentDidUpdate / componentWillUnmount
2. useEffect的
参数一:执行的回调函数;
参数二: 该useEffect在哪些state发生变化时,才重新执行;(受谁的影响)可以起到优化的作用;

比如: 某些代码我们只是希望执行一次即可,类似于componentDidMount和componentWillUnmount中完成的事情;(比如网
络请求、订阅和取消订阅);第二个参数传: [ ] 即可;
比如:组件更新时,会先执行组件的销毁,再重新的更新组件, 这样就会频繁执行销毁中的操作, 第二个参数传: [ ] 即可;
比如: 同一个组件中有多个数据,但只希望其中的一个数据(count)变化时重新渲染组件, 第二个参数传: [count] 即可;

类组件中:
import React, { PureComponent } from 'react'

export default class ClassCounterTitleChange extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: 0
    }
  }

  componentDidMount() {
  // 1. 组件第一次渲染时执行
    // 修改DOM
    document.title = this.state.counter;

    // 订阅事件
    console.log("订阅一些事件");

    // 网络请求
  }

  componentWillUnmount() {
  // 3. 组件销毁时执行
    console.log("取消事件订阅");
  }

  componentDidUpdate() {
  // 2. 组件更新时执行
    document.title = this.state.counter;
  }

  render() {
    return (
      <div>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={e => this.setState({counter: this.state.counter + 1})}>+1</button>
      </div>
    )
  }
}

函数式组件中使用hook- useEffect
import React, { useState, useEffect } from 'react'

export default function HookCounterChangeTitle() {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
  // 1. 组件 第一次渲染(相当于componentDidMount);
  // 2. 组件更新时执行(相当于componentDidUpdate);
    document.title = counter;
  },[counter])
  
   useEffect(() => {
  // 1. 组件 第一次渲染,比如:订阅事件;
    return ()=> {
      // 2. 组件销毁时 会执行这个返回值的回调函数(相当于componentWillUnmount),比如:取消事件订阅;
    }
  },[])

  return (
    <div>
      <h2>当前计数: {counter}</h2>
      <button onClick={e => setCounter(counter + 1)}>+1</button>
    </div>
  )
}

三.useContext

在之前的开发中,我们要在组件中使用共享的Context有两种方式:

  1. 类组件可以通过 类名.contextType = MyContext方式,在类中获取context;
  2. 多个Context或者在函数式组件中通过 MyContext.Consumer 方式获取共享context; 但是多个Context共享时的方式会存在大量的嵌套:在这里插入图片描述
  3. Context Hook允许我们通过Hook来直接获取某个Context的值;
    在这里插入图片描述
    注意:
    当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重新渲染,并使用最新传递给 MyContext provider 的 context value 值。

四. useReducer

useReducer仅仅是useState的一种替代方案:

  1. 在某些场景下,如果state的处理逻辑比较复杂,我们可以通过useReducer来对其进行拆分;
  2. 或者本次修改的state需要依赖之前的state时,也可以使用;
    在这里插入图片描述
    注意:
    很多人看到useReducer的第一反应应该是redux的某个替代品,其实并不是。数据是不会共享的,它们只是使用了相同的counterReducer的函数而已。 所以,useReducer只是useState的一种替代,并不能替代Redux。

五.useContext+useReducer实现Redux

useContext: 实现数据的动态共享;
useReducer: 数据更改逻辑处理,实现数据的更新;
组合在一起就可以实现Redux的效果!!!

实现的效果:
在这里插入图片描述
在这里插入图片描述

**Color组件中逻辑:**

import React, { createContext, useReducer } from 'react';
export const ColorContext = createContext();
export const UPDATA_COLOR = 'UPDATE_COLOR';

// reducer-处理state数据:
function ColorReducer(state, action) {
  switch (action.type) {
    case UPDATA_COLOR:
      return action.color;

    default:
      return state;
  }
}

export function Color(props) {
  const [color, dispatch] = useReducer(ColorReducer, 'yellow');
  return (
    <div>
    // 向所有子组件中共享数据:
      <ColorContext.Provider value={{ color, dispatch }}>
        {props.children}
      </ColorContext.Provider>
    </div>
  );
}

**用户操作组件中:**

import React, { useContext } from 'react';
import { ColorContext, UPDATA_COLOR } from './03_color';

export default function User() {
// 获取共享的dispatch:
  const { dispatch } = useContext(ColorContext);
  return (
    <div style={{ padding: 20 }}>
      <button onClick={() => dispatch({ type: UPDATA_COLOR, color: 'red' })}>
        变红色
      </button>
      <button onClick={() => dispatch({ type: UPDATA_COLOR, color: 'blue' })}>
        变蓝色
      </button>
    </div>
  );
}

**使用state数据的组件中:**

import React, { useContext } from 'react';
import { ColorContext } from './03_color';

export default function Home() {
  const { color } = useContext(ColorContext);

  return <div style={{ color: color }}>我现在是什么颜色</div>;
}

六. useCallback

  1. useCallback实际的目的是为了进行性能的优化。
  2. 如何进行性能的优化呢?
    2.1 useCallback会返回一个回调函数的 memoized(记忆的) 值;
    2.2 在依赖不变的情况下,多次定义的时候,返回的回调函数是相同的
    在这里插入图片描述
    注意:通常使用useCallback的目的是不希望子组件进行多次渲染,并不是为了函数进行缓存.

七. useMemo

  1. useCallback实际的目的是为了进行性能的优化。
  2. 如何进行性能的优化呢?
    2.1 useCallback会返回一个回调函数返回值的 memoized(记忆的) 值;
    2.2 在依赖不变的情况下,多次定义的时候,回调函数返回的值是相同的;

案例:
案例一:进行大量的计算操作,是否有必须要每次渲染时都重新计算;
在这里插入图片描述
案例二:对子组件传递相同内容的对象时,使用useMemo进行性能的优化在这里插入图片描述

八. useRef

  1. useRef返回一个ref对象,返回的ref对象再组件的整个生命周期保持不变。
  2. 最常用的ref是两种用法:
    用法一:引入DOM(或者组件,但是需要是class组件)元素;
    用法二:保存一个数据,这个对象在整个生命周期中可以保存不变;

案例一:引用DOM
在这里插入图片描述
案例二:使用ref记录上一次的某一个值
在这里插入图片描述

九. useImperativeHandle

先来回顾一下ref和forwardRef结合使用:

  1. 通过forwardRef可以将ref转发到子组件;
  2. 子组件拿到父组件中创建的ref,绑定到自己的某一个元素中;
    在这里插入图片描述

forwardRef的做法本身没有什么问题,但是我们是将子组件的DOM直接暴露给了父组件:

  1. 直接暴露给父组件带来的问题是某些情况的不可控;父组件可以拿到DOM后进行任意的操作;
  2. 但是,事实上在上面的案例中,我们只是希望父组件可以操作focus,其他并不希望它随意操作;

通过useImperativeHandle可以值暴露固定的操作:

  1. 通过useImperativeHandle的Hook,将传入的ref和useImperativeHandle第二个参数返回的对象绑定到了一起;
  2. 所以在父组件中,使用 inputRef.current时,实际上使用的是返回的对象; 比如我调用了 focus函数,甚至可以调用 hello函数;
    在这里插入图片描述
    在这里插入图片描述

十. useLayoutEffect

  1. useEffect会在渲染的内容更新到DOM上执行,不会阻塞DOM的更新;
  2. useLayoutEffect会在渲染的内容更新到DOM上之前执行,会阻塞DOM的更新;
    在这里插入图片描述
    注意:如果我们希望在某些操作发生之后再更新DOM,那么应该将这个操作放到useLayoutEffect;

十一. 自定义hook

自定义Hook本质上只是一种函数代码逻辑的抽取,严格意义上来说,它本身并不算React的特性;
应用: 可以抽离公共逻辑;
注意:自定义hook名要以use开头;

案例演示:
案例一: 所有的组件在创建和销毁时都进行某些相同的操作;
在这里插入图片描述
案例二: 组件实时获取滚动的位置;

自定义hook usePosition:
import React, { useState, useEffect } from 'react';

export default function usePosition() {
  const [postion, setpostion] = useState(0);
  useEffect(() => {
    function scrollFn() {
      setpostion(window.scrollY);
    }
    document.addEventListener('scroll', scrollFn);
    return () => {
      document.removeEventListener('scroll', scrollFn);
    };
  }, []);
  return postion;
}

使用:
import React from 'react';
// 引入自定义的hook:
import usePosition from './hooks/usePosition';

export default function DefineHook() {
  return (
    <div style={{ height: '200px' }}>
      <div style={{ height: '2000px', backgroundColor: 'green' }}>
              <h3 style={{ position: 'fixed', top: 0, left: 0 }}>
         {/* 直接调用自定义的hook */}
          我在滚动,位置{usePosition()}
        </h3>
      </div>
    </div>
  );
}
ReactHooks是一种特殊的函数,它们允许我们在函数组件使用状态和其他React特性,而不需要使用类组件。使用Hooks可以使得代码更简洁、易读,并且更方便进行状态管理和副作用的处理。 React提供了一些常用的Hooks,其最常见的是useState和useEffect。 1. useState:useState允许我们在函数组件声明和使用状态。它接受一个初始值作为参数,并返回一个包含当前状态和更新状态的数组。我们可以通过解构赋值来获取状态和更新状态的函数。例如: ``` const [count, setCount] = useState(0); ``` 这段代码声明了一个名为count的状态变量,并将初始值设置为0。setCount是一个函数,用于更新count的值。 2. useEffect:useEffect用于在组件渲染完成后执行一些副作用操作,比如发送网络请求、订阅事件等。它接受两个参数:一个副作用函数和一个依赖数组。副作用函数会在组件渲染完成后执行,而依赖数组用于指定何时重新执行副作用函数。 ``` useEffect(() => { // 执行副作用操作 // 返回一个清理函数(可选) }, [依赖数组]); ``` 依赖数组的值发生变化时,副作用函数会被重新执行。如果依赖数组为空,则副作用函数只会在组件首次渲染后执行一次。 除了useState和useEffect,React还提供了其他一些常用的Hooks,如useContext、useReducer、useCallback等,用于处理不同的需求。使用Hooks可以使我们更好地组织和管理组件的逻辑,使代码更易维护和复用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值