React Hooks

React Hooks

前言

react hooksreact 16.8.0版本开始推广的。

class声明的组件我们称之为有状态组件,function声明的组件我们称之为无状态组件。

  • 有状态组件拥有自己的状态和生命周期,在复用组件时我们需要考虑复用时是否对其自身状态造成影响。而函数组件数据全部依赖于props传入,更易管理。
  • 有状态组件通常我们数据初始化在componentDidMount生命周期,数据更新需要在componentDidUpdate再次重置自身状态。当项目复杂化后,这部分的代码维护容易被遗漏。
  • 有状态组件都有自身的this指向,很容易在事件绑定中被遗忘。

对于冗长难以复用的有状态组件,很容易陷入多层级状态嵌套问题,react提出了2种解决方案。

渲染属性:使用一个函数类型的props值来传递子组件,让组件更加精炼明细。

高阶组件:通过函数传入一个组件,返回一个新的组件,达到组件的细化。

hooks的出现就是解决状态共享问题,在上面2种解决方案的下再次推广一种新的状态解决方案–函数型组件

函数类型的组件写法平铺,易于将UI和状态分离。
可根据依赖进行状态变化的实时处理,避免了大量的优化操作。

无状态函数组件本身并不具备状态和生命周期,它可以做到最小化设计,并且方便复用和独立测试。

react为了让组件更加具有复用性,提出了react hook,其解决了原始函数组件不具备自身状态,生命周期,this指向等问题,并且优化了部分有状态组件的手工操作。hooks相互间的引用也是基于函数级的,更加便捷。

React hooks只是为了让函数类型的组件可以便捷复用,与class类型的组件并无明显的差异,2者都可通过自己的方式实现组件细化和封装。

useState

const [state, setState] = useState(initialState);

相当于类组件的this.state,但是useState可以接受任意类型的参数,而this.state={}

参数initialState,任意类型的数据

返回值:一个数组,包含2个值。第一个值是当前state的值,第二个值是一个函数,可以用于设置当前state的值。

第二个返回值setState((prevState)=>{ return newState})。其接受上一次状态值作为参数,返回一个新的值。相当于class中的setState({}),但是useState的第二返回值,并不会合并state,而是直接替换上一次的值。

  • setState完成后会直接进行render,但是在render外获取state的值并不会改变,需要配合useEffect监听该状态的改变才能正常使用

注意

  • hooks是有序的,会被react从上到下依次读取,所以不能在条件中使用,这样会导致解析的时候前后声明顺序不一致。hooks必须放在函数内部顶层。

useEffect

useEffect(()=>{
	//逻辑处理
	//组件卸载
	//return ()=>{}
},[stateNameArr])

useEffect又称为副作用,主要用于替代class的生命周期。每次render后都会调用该函数。

参数

  • 第一参数:function,定义逻辑处理。允许返回一个回调函数,该回调函数会在组件卸载的时候执行。

  • 第二参数:array,定义哪些状态改变会调用该方法的第一参数,执行其逻辑。

    这里系统内部处理了前后两次状态的比较,如果有差异才会执行,否则跳过。

    • 如果参数是个空数组,则相当于componentDidMount生命周期
    • 如果数组中有值,则相当于componentDidUpdate生命周期,且数组中定义的任意状态的改变都将被触发。

返回值:一个回调函数,非必须。如果存在,则在组件卸载时执行componentWillUnmount生命周期。

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

interface TestProps { };

const Test: React.FC = ({ }) => {

    const [count, setCount] = useState(0);
    const [addClickNum, setAddClickNum] = useState(0);
    const [title, setTitle] = useState('React Hooks');

    useEffect(()=>{
        //初始化项目,相当于componentDidMount
        let titleDom = document.getElementById("title");
        titleDom.innerText = "React Hooks Title"
    },[])

    useEffect(()=>{
        //当count改变时进入,相当于componentDidUpdate
        let titleDom = document.getElementById("title");
        titleDom.innerText = "React Hooks " + count; 

        //如果有返回函数则相当于componentWillUnmount
        return ()=>{
            console.log("卸载组件") 
        }
    },[count])

    

    const addCount = () => {
        setCount(count => ++count);
        setAddClickNum((state) => ++state)
    }

    const subCount = () => {
        setCount(count => --count);
    }

    return (
        

{title}

统计数:{count}
添加点击数:{addClickNum}
); }; export default Test;

这我们发现我们定义了2次useEffect,一次相当于初始化,另一次表示count值改变时调用。实际上只要定义了useEffect,无论第二参数有值无值,都经会执行一次初始化操作,而非有值的情况下只进行更新逻辑。

所以我们会发现页面的标题只显示第二次的设置,第一次的定义被覆盖掉了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FiAKADDh-1589973766532)(/Users/windeye/Desktop/图片/effect_hooks.png)]

useRef

const refContainer = useRef(initialValue);

相当于class组件中的ref属性,但是它区别于ref在于它不是一个纯的dom元素或者实例,而是一个js对象。其current属性代表dom元素或者实例。

参数:任意值,可用于存储跨生命周期的变量。

返回值:一个对象,仅包含一个current属性。

  • 如果用ref使用了它,则表示ref对应的dom元素或者实例。
  • 如果未用ref声明,则相当于一个缓存对象,current属性缓存指定的变量。

注意事项

  • ref对象变化时,useRef并不会接收到通知。
  • 变更current属性也不会引发组件重新渲染。

useImperativeHandle

useImperativeHandle(ref, createHandle, [deps])

seImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。

useImperativeHandle 需要与 forwardRef配套使用。

const refComponent = React.forwardRef((props,ref)=>{return ...})

forwardRef会创建一个组件,并将组件接收的ref属性传递到其任意子组件。从而达到父组件可以直接调用子组件的方法实例。

import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
import { Button } from 'antd';

const Title: any = ((props, ref) => {
    const [title, setTitle] = useState('React Hooks');
    //第二个参数为一个返回一个对象,其可以自定义ref的属性
    useImperativeHandle(ref, () => ({
        getTitle: () => {
            return title
        }
    }))

    return (

{title}

) }) //搭配forwardRef使用 const FcTitle = forwardRef(Title); interface TestProps { }; const Test: React.FC = ({ }) => { const [count, setCount] = useState(0); const [addClickNum, setAddClickNum] = useState(0); const testRef = useRef(null); useEffect(() => { if (testRef.current) { let title = testRef.current.getTitle() console.log(title) } }, []) const addCount = () => { setCount(count => ++count); setAddClickNum((state) => ++state) } const subCount = () => { setCount(count => --count); } return (
统计数:{count}
添加点击数:{addClickNum}
); }; export default Test;

useCallBack

const callBack = useCallBack(fn,deps)

参数

  • 第一参数,一个回调函数
  • 第二参数,依赖项

返回值:一个memoized回调函数。

常用于定义传递给子组件的函数,因为函数组件无法绑定this,所有可以根据回调函数的形式传递给子组件。

注意事项

  • 依赖项数据不会作为参数传递给回调函数,仅作为更新回调函数的凭证。
  • 所有的回调函数参数,均应出现在依赖项中,方便未来智能解析。
  • 一般用于缓存函数

useMemo

const memoValue = useMemo(fn,deps)

相当于

const memoValue = useCallBack(()=>fn,deps)

参数

  • 第一参数,一个回调函数,可接受props等参数
  • 第二参数,依赖项

返回值:一个memoized值。

useMemo会立即执行回调函数,并返回其结果值。

注意事项

  • 依赖项数据不会作为参数传递给回调函数,仅作为更新结果值的凭证。
  • 所有的回调函数参数,均应出现在依赖项中,方便未来智能解析。
  • 如果没有依赖项,那么每次渲染都会执行useMemo
  • 相当于shouldComponentUpdate的替代方案。
  • 一般用于缓存组件

useReducer

const [state, dispatch] = useReducer(reducer, initialState, init);

useReduceruseState的替代方案,对于多层级组件的传值,帮助较大。类似于redux的流程处理。

参数

  • 第一参数:const reducer = (state,action)=>{...},接收一个reducer纯函数,返回一个新的state。
  • 第二参数:初始化state的值。
  • 第三参数:一个接收第二参数的函数,const init = (initialState)=>{},用于惰性初始化,方便重置操作。

返回值

  • 第一结果值:state,当前状态
  • 第二结果值:dispath,转发函数,接收一个对象参数{type:actionName}

注意事项:

  • 可以用useReducerdispatch来模拟forceUpdate,实质也是状态改变,然后重绘组件。
import React, { useReducer } from 'react';
import { Button } from 'antd';

interface CountProps {
    state: any,
    dispatch: any
};
const Count: React.FC = ({ state, dispatch }) => {
    return (
        
统计数:{state.count}
) } interface TestProps { }; const Test: React.FC = ({ }) => { //定义reducer const reducer = (state, action) => { switch (action.type) { case 'add': return { count: state.count + 1 } case 'sub': return { count: state.count - 1 } } } //初始化状态 const [state, dispatch] = useReducer(reducer, { count: 0 }); return (

React Hooks

); }; export default Test;

你可能感兴趣的:(React)