react hook基本使用

react hook基本使用

  • react 16.8版本出现的新特性,解决了类组件的一些问题,消除了繁琐的声明周期,使我们的开发更方便,bug出现的更少,代码更直观。【重点是前两个hook】

useState(转态管理,功能和类组件的state类似)

  • 在函数组件的函数体中调用这个函数(useState),参数为转态默认值,返回一个数组,数组的第一个元素为状态的值,第二个元素为一个函数,为用于改变状态的函数。

    import React, {useState} from "react";
    
    export default function UseStateTest() {
        const [n, setN] = useState(0);
        return <>
            <div>{n}</div>
            <button onClick={() => {
                setN(1);//将n变为1
            }
            }>点击改变
            </button> 
        </>
    }
    
  • 每次调用setN(新值)如果新值和旧的值不同,那么组件就会重新渲染,需要注意的是,如果setN()的参数直接传递一个新的值,那么这个改变是异步的,如果调用多次这个改变,拿到的值都是原始值。

    export default function UseStateTest() {
        const [n, setN] = useState(0);
        return <>
            <div>{n}</div>
            <button onClick={() => {
                setN(n + 1);//n由0变为1
                setN(n + 1);//n由0变为1
                console.log(n);//0
            }
            }>点击改变
            </button>
        </>
    }
    

    如果想要使用最新的值,就可以将一个回调函数作为参数传入setN,函数的第一个形参为上一个改变的新的状态值,回调函数的返回值为新的状态值。

    export default function Test() {
        const [n, setN] = useState(0);
        return <>
            <div>{n}</div>
            <button onClick={() => {
                setN(preValue => {
                    console.log(preValue);//0
                    return preValue + 1;
                })
                console.log("第一个同步打印", n);
                setN(preValue => {
                    console.log(preValue);//1
                    return preValue + 1;
                })
                console.log("第二个同步打印", n);
                setN(preValue => {
                    console.log(preValue);//2
                    return preValue + 1;
                })
                console.log("第三个同步打印", n);
            }
            }>点击改变
            </button>
        </>
    }
    

    打印结果:
    0
    ​ 第一个同步打印 0
    ​ 第二个同步打印 0
    ​ 第三个同步打印 0
    ​ 1
    ​ 2

    通过打印的结果和顺序可以得出结论,在react合成事件中,第一个setN()的回调函数先执行,接下来的setN()的回调函数放到队列异步执行,setN是异步执行的,每一个setN()中的回调函数的形参都是上一个setN()返回的新状态。

  • 常常我们需要使用多个状态,一个组件中不相干状态分离也是符合react的设计理念,所以我们就需要在一个函数组件中调用多次useState,

  • 需要注意的是,如果状态值是一个对象,那么每次改变函数的新状态值是直接替代旧的对象,而不是覆盖,这点和类组件的转态相同,所以如果需要改变状态对象的某个值时,应该先用展开运算符将之前的转态值展开,在用新的转态值覆盖之前的状态值,从而产生一个新的对象,包含原来其他状态和新的状态。

    export default function UseStateTest() {
        const [n, setN] = useState({
            content: 'hello',
            like:'java'
        });
        return <>
            <div>{n.content}</div>
            <div>{n.like}</div>
            <button onClick={() => {
                setN({
                    ...n,
                    content: 'world'
                })
            }
            }>点击改变
            </button>
        </>
    }
    
  • 很多人会有一个疑问,当一个函数组件使用了多个转态时,改变其中一个状态,组件重新渲染,那么其他状态为什么能够保持原来的转态数据,而不会重置。

    • 可以想象有一个附着在附件的记录表,记录所有hook的下标值和状态信息。每当使用一个useState的时候,就会增加一个记录,比如第一个记录下标值为0,转态值为默认状态,第二次使用useState增加一条记录下标值为1,转态值为默认状态,当使用setN()改变状态值后就会用新的状态值代替记录表中原有的状态值,每次重新渲染组件,也会从状态表中根据下标值获取对应转态值。
    • 这也是不能将hook放到判断语句和循环语句的原因,不仅仅useState,所有hook都不可以这样做,这样做可能会造成下标值和信息对应错乱。
  • 每个useState附着在组件节点上互不影响,所以就算调用了两次这个函数组件,他们的状态值也不会共享。

useEffect(处理副作用操作函数)

  • 副作用操作指的是会对组件外部产生影响的操作。
  • 如ajax请求,计时器,更改真实dom等等。
  • useEffect接受一个回调函数作为参数,接收的回调函数用来处理副作用操作,这个回调函数就是副作用函数。
    1. 副作用函数运行的时间是在页面完成ui渲染之后,他的执行是异步的不会阻塞页面。
    2. 与componentDidMount和componentDidUpDate的区别在于这两个生命周期函数运行在更新了真实dom数但用户还没有看到页面的时候,useEffect发生在用户看到页面后。
  • 副作用函数可以返回一个函数,这个函数是清理函数,清理函数首次加载不会运行,更新副作用函数时运行,运行时间在副作用函数之前。
  • useEffect函数可以传第二个参数,是一个数组,数据中每一个元素记录副作用函数依赖的数据,组件重新渲染后,只有依赖数据改变后,副作用函数才会重新执行。
    • 所以当传递了第二个参数依赖数据,当依赖数据不变时,
    1. 副作用函数仅在第一次渲染后执行。
    2. 清理函数仅在卸载组件后执行。
  • 在副作用函数中,如果使用了函数上下文的变量,由于闭包的影响,会导致副作用函数不会实时变化。

useContext(更优秀简洁的上下文解决方案)

import React, {useContext} from "react";
const ctx = React.createContext();
function Son() {
  const value = useContext(ctx);//直接拿到父组件提供的value值。
  return <div>{value.name}</div>//渲染react
}
export default function UseStateTest() {
    return <>
        <ctx.Provider value={{name:'react'}}>
            <Son/>
        </ctx.Provider>
    </>
}

自定义hook(将一些常用的,跨越多个组件的hook功能,抽离成一个函数,这个函数就是自定义hook)

  • 自定义hook更新组件,使用它的组件也会更新,可以用来封装异步请求方法,api接口。

useCallback(固定函数地址,用于优化)

import React, {useState} from "react";

class Son extends React.PureComponent {
    render() {
        console.log("Test渲染");
        return <button onClick={this.props.myClick}>点击子组件{this.props.num}</button>
    }
}

export default function Test() {
    const [n, setN] = useState(0);
    const [s, setS] = useState(0);
    console.log("父组件渲染");
    return <>
        <Son num={s} myClick={() => {
           setS(10);
        }
        } />
        <button onClick={() => {
            setN(n+1);
        }
        }>点击父组件
        </button>
    </>
}
  • 有可能遇到上面的场景,Son为纯组件,父组件刷新后,当传入props和自身state不变时,组件不重新渲染,但是每次点击父组件按钮,传入Son的props看起来没有改变,他自身也没有state,应给不会刷新才对,但是他却刷新了,原因在于Son传入的myClick函数每次刷新父组件都会产生一个新的函数赋值给myClick,也就是props变了,所以组件会刷新。
  • 如果将函数写在外面的话,setS就没办法传过去了,这样的需求useCallback就可以很好地处理了。看看下面的代码。
import React, {useCallback, useState} from "react";

class Son extends React.PureComponent {
    render() {
        console.log("Test渲染");
        return <button onClick={this.props.myClick}>{this.props.num}点击子组件</button>
    }
}

export default function Test() {
    const [n, setN] = useState(0);
    const [s, setS] = useState(0);
    const handleClick = useCallback(()=>{
        setS(10);
    },[s]);
    console.log("父组件渲染");
    return <>
        <Son num={s} myClick={handleClick} />
        <button onClick={() => {
            setN(n+1);
        }
        }>点击父组件
        </button>
    </>
}
  • useCallback()第一个参数是一个回调函数,第二个参数是一个依赖数组,返回一个函数,返回的函数就是回调函数的引用,如果依赖数组的数据不发生变化,那么返回的就永远是同一个函数的引用,这样就可以完美解决上面的问题。

useMemo(保持不需要重新计算的稳定数据,用于性能优化)

  • 用法类型于useCallback,不同的是回调函数里返回的内容是需要记忆的内容
    const handleClick = useMemo(()=>{
        return ()=>{
            setS(10);
        }
    },[s]);

上面的固定函数可以写成如上代码,效果相同,由于useMemo返回值记忆的是return返回的值,所以这个hook有更多的应用场景,固定各种类型的变量。只要一赖数据不变,返回的值的引用就不变,可以将不需要的计算放到useMemo的第一个参数回调函数当中。(有点像vue的computed计算属性)

useRef(多个对象同一个引用,性能优化)

  • 调用这个函数,返回一个对象{current:undefined},如果调用useRef时传一个参数,则返回对象的current的值为那个参数。
  • 如果使用React.creatRef由于每一次函数组件重新渲染都会重新创建一个新的ref,对性能有一些影响,使用useRef无论重新调用函数多少次,使用的都是同一个返回值ref
  • 利用useRef同一引用值这个特性写个倒计时
import React, {useEffect, useRef, useState} from "react";

export default function UseStateTest() {
    const [n, setN] = useState(10);
    const val = useRef(n);
    useEffect(() => {
        const timer = setInterval(() => {
            setN(val.current--);
            if (val.current === 0) {
                clearInterval(timer);
            }
        }, 500);
    }, [])
    return <div>
        {n}
    </div>
}
  • 由于每一次都使用同一个val引用,所以每次重新渲染函数都使用同一个引用。

useLayoutEffect(作用和useEffect相同)。【不常用

  • 差别在于副作用函数运行的时间点,useLayoutEffect在dom构建完成,但还没有渲染ui页面的时候运行,和生命周期函数componentDidMount和componentDidUpdate函数运行的时间点差不多。应该尽量使用useEffect,因为这个hook不会阻塞ui页面,如果有特殊需求,再考虑使用useLayoutEffect。

useImperativeHandle这个hook用于使用ref调用函数组件的方法。【不常用

useDebugValue 用于自定义hook的关联数据显示到调试栏。如果创建的自定义hook通用性比较高,可以使用这个hook方便调试。【不常用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前言如释重负,好用的技术就应该越来越简单React Hooks 是 React 16.8 从提案转为正式加入的新特性。这个新特性是个非常棒的设计。 可以说对于React 技术栈的发展具分割线一样的意义。讲师在课程中提到:之前使用 React 作为主要的前端技术,开发一款网页游戏。在整个游戏的各个模块中,Redux ,mobx,以及蚂蚁金服的 ant-design,dva, umi 这些框架或者第三方库都有涉及使用。但是自从了解了Facebook官方提案的 Hooks 特性后,才真正觉得获得了前所未有的解脱。如果你有React开发经验,学习了解 Hooks 后,一定有一种如释重负的轻松感。React 带来了方便也带来了迷茫相信关心 React Hooks 这项新特性的童鞋,很多已经有了一定的 React 开发经验。那么你一定有所体验,React 给我们带来方便的同时,也的确和长久以来的前端开发模式有极大的不同。React 并不需要用继承,而是推荐用嵌套。React 有独特的 jsx 语法。大多数情况 jsx 都使得我们的代码更加简洁了。然而有些时候也给我们带来了一些困扰。 比如数据的传递,逻辑的复用。 react 是一种 mvvm 的设计模式,作为开发者一定要清楚,那些数据是业务数据,那些数据是UI数据。否则你的代码很有可能会陷入混乱局面。大型项目中模块化与功能解耦困难在公司项目中 App 稍大的时候,我们发现状态提升和只通过 props 进行数据传递。很多时候都很难实现我们的需求。这时无论我们是否清楚的了解,但是状态管理也就是 redux mobx 等,轻易地进入到了公司的项目中。我们经过初期的尝试发现状态管理,确实比用纯粹的 React 带来了数据传递上的方便,以及代码组织上的清晰。但前提是你看懂且理解了 redux 大神晦涩的官网文档。 本来 React 被设计用来组件化前端开发。但当我们初期使用状态管理,我们常常会过度的使用状态数据,业务逻辑和ui逻辑没有清楚的分离,最终你的应用代码结果可能是:除了少数几个组件是独立的解耦的,大多数组件都因为状态数据的共享而耦合在了一起,且他们也完全依赖状态管理框架。无法再轻松的转移复用。使用高阶组件,属性渲染,渲染回调等高级特性,确实可以帮我们解决模块或功能的解耦问题。但是这些方法,确实有点超出普通“猿类”的技能。且降低了代码的可读性,对于团队协作,这是很致命的问题。React Hooks 真正开启前端模块化的金钥匙对于以上问题,React Hooks 都有很好的解决方案,官方的设计动机就是解决这些曾经的繁琐,化繁为简。React Hooks 让我们在纯函数中就可以使用 React 的众多特性。而不必使用类。代码扁平,易读。解耦状态相关逻辑,UI逻辑和业务逻辑更好的分离。这些逻辑往往是纯函数,而以前很容易混合在类组件中。通过自定义 Hooks 我们可以把应用中“状态相关”逻辑解耦出来,独立编写到我们自己的hooks 中。从而更加易于复用和独立测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值