React Hook用法示例详解(6个常见hook)


Posted in Javascript onApril 28, 2021

1、useState:让函数式组件拥有状态

用法示例:

// 计数器
import { useState } from 'react'
const Test = () => {
    const [count, setCount] = useState(0);
    return (
        <>
            <h1>点击了{count}次</h1>
            <button onClick={() => setCount(count + 1)}>+1</button>
        </>
    );
}
export default Test

PS:class组件中this.setState更新是state是合并, useState中setState是替换。例如:

// 错误示例
import { useState } from 'react'
const Test = () => {
    const [counts, setCounts] = useState({
        num1: 0,
        num2: 0
    });
    return (
        <>
            <h1>num1:{counts.num1}</h1>
            <h1>num2:{counts.num2}</h1>
            <button onClick={() => setCounts({ num1: counts.num1 + 1})}>num1+1</button>
            <button onClick={() => setCounts({ num2: counts.num2 + 1})}>num2+1</button>
        </>
    );
}
export default Test

React Hook用法示例详解(6个常见hook)

可以看到useState中setState是替换,不会合并,正确更新:

import { useState } from 'react'
const Test = () => {
    const [counts, setCounts] = useState({
        num1: 0,
        num2: 0
    });
    return (
        <>
            <h1>num1:{counts.num1}</h1>
            <h1>num2:{counts.num2}</h1>
            <button onClick={() => setCounts({ ...counts, num1: counts.num1 + 1})}>num1+1</button>
            <button onClick={() => setCounts({ ...counts, num2: counts.num2 + 1})}>num2+1</button>
        </>
    );
}
export default Test

2、useEffect:副作用,取代生命周期

用法示例,在class组件中如果需要在组件挂载后和数据更新后做同一件事,我们会这样做:

componentDidMount() {
    // 做一些事
}
componentDidUpdate() {
    // 做一些事
}

可以看出来,如果逻辑复杂后,代码看起来不优雅,且容易造成逻辑混乱,而使用useEffect:

useEffect(() => {
    // 做一些事
});

此刻已经看到了useEffect的基本用法,除此之外,他还可以绑定触发更新的依赖状态,默认是状态中任何数据发生变化副作用都会执行,如:

import { useState, useEffect } from 'react'
const Test = () => {
    const [count1, setCount1] = useState(0);
    const [count2, setCount2] = useState(0);
    useEffect(() => {
        console.log('useEffect触发了')
    });
    return (
        <>
            <h1>count1:{count1}</h1>
            <h1>count2:{count2}</h1>
            <button onClick={() => setCount1(count1 + 1)}>count1+1</button>
            <button onClick={() => setCount2(count2 + 1)}>count2+1</button>
        </>
    );
}
export default Test

React Hook用法示例详解(6个常见hook)

将上述代码useEffect第二个参数传入需要绑定的状态,可绑定多个:

// 语法:useEffect(回调函数,[依赖值])
useEffect(() => {
    console.log('useEffect触发了')
}, [count1]);

React Hook用法示例详解(6个常见hook)

可以看到,只有绑定的count1发生变化才会触发,如果传空数组则任何状态发生变化都不会触发,此时useEffect的作用就类似class组件中的componentDidMount,所以发送请求通常也会在此执行。

清理副作用

在上面的操作中都不用清理的副作用,然而,有些副作用是需要去清理的,不清理会造成异常甚至内存泄漏,比如开启定时器,如果不清理,则会多次开启,从上面可以看到useEffect的第一个参数是一个回调函数,可以在回调函数中再返回一个函数,该函数可以在状态更新后第一个回调函数执行之前调用,具体实现:

useEffect(() => {
    // 设置副作用
    return () => {
        // 清理副作用
    }
});

3、useContext:跨组件共享数据

React.createContext();创建一个TestContext对象
TestContext.Provider包裹子组件
数据放在<TestContext.Provider value={value}>的value中
子组件中通过useContext(TestContext)获取值

import React, { useContext, useState } from 'react';
const TestContext = React.createContext();
const Parent = () => {
    const [value, setValue] = useState(0);
    return (
        <div>
            {(() => console.log("Parent-render"))()}
            <button onClick={() => setValue(value + 1)}>value + 1</button>
            <TestContext.Provider value={value}>
                <Child1 />
                <Child2 />
            </TestContext.Provider>
        </div>
    );
}
const Child1 = () => {
    const value = useContext(TestContext);
    return (
        <div>
            {(() => console.log('Child1-render'))()}
            <h3>Child1-value: {value}</h3>
        </div>
    );
}
const Child2 = () => {
    return (
        <div>
            {(() => console.log('Child2-render'))()}
            <h3>Child2</h3>
        </div>
    );
}
export default Parent

React Hook用法示例详解(6个常见hook)

至此数据实现共享了,但是可以看到在TestContext中的共享数据只要发生变化,子组件都会重新渲染,Child2并没有绑定数据,不希望他做无意义的渲染,可以使用React.memo解决,实现:

const Child2 = React.memo(() => {
    return (
        <div>
            {(() => console.log('Child2-render'))()}
            <h3>Child2</h3>
        </div>
    );
});

React Hook用法示例详解(6个常见hook)

4、useCallback:性能优化

语法:

// useCallback(回调函数,[依赖值])
const handleClick = useCallback(()=> {
    // 做一些事
}, [value]);

useCallback返回的是一个 memoized(缓存)函数,在依赖不变的情况下,多次定义的时候,返回的值是相同的,他的实现原理是当使用一组参数初次调用函数时,会缓存参数和计算结果,当再次使用相同的参数调用该函数时,会直接返回相应的缓存结果。

优化性能例子:

import React, { useState, useCallback, memo } from 'react';
const Parent = () => {
    const [value1, setValue1] = useState(0);
    const [value2, setValue2] = useState(0);
    const handleClick1 = useCallback(()=> {
        setValue1(value1 + 1);
    }, [value1]);
    const handleClick2 = useCallback(()=> {
        setValue2(value2 + 1);
    }, [value2]);
    return (
        <>
            {(() => console.log("Parent-render"))()}
            <h3>{value1}</h3>
            <h3>{value2}</h3>
            <Child1 handleClick1={handleClick1} />
            <Child2 handleClick2={handleClick2} />
        </>
    );
}
const Child1 = memo(props => {
    return (
        <div>
            {(() => console.log("Child1-render"))()}
            <button onClick={() => props.handleClick1()}>value1 + 1</button>
        </div>
    );
});
const Child2 = memo(props => {
    return (
        <div>
            {(() => console.log("Child2-render"))()}
            <button onClick={() => props.handleClick2()}>value2 + 1</button>
        </div>
    );
});
export default Parent

React Hook用法示例详解(6个常见hook)

useCallback返回的是一个memoized回调函数,仅在其中绑定的一个依赖项变化后才更改可防止不必要的渲染,在跨组件共享数据中举例的事件是在父组件中点击触发,而现在是使用状态提升,在父组件中传递方法供子组件调用,每次render时函数也会变化,导致子组件重新渲染,上面例子useCallback将函数进行包裹,依赖值未发生变化时会返回缓存的函数,配合React.memo即可优化无意义的渲染。

5、useMemo:性能优化

语法:

// useMemo(回调函数,[依赖值])
useMemo(() => {
    // 做一些事情
},[value]);

先看一个例子:

import React, { useState } from 'react'
const Test = ()=> {
    const [value, setValue] = useState(0);
    const [count, setCount] = useState(1);
    const getDoubleCount = () => {
        console.log('getDoubleCount进行计算了');
        return count * 2;
    };
    return (
        <div>
            <h2>value: {value}</h2>
            <h2>doubleCount: {getDoubleCount()}</h2>
            <button onClick={() => setValue(value + 1)}>value+1</button>
        </div>
    )
}
export default Test

React Hook用法示例详解(6个常见hook)

可以看到getDoubleCount依赖的是count,但value发生变化它也重新进行了计算渲染,现在只需要将getDoubleCount使用useMemo进行包裹,如下:

import React, { useState, useMemo } from 'react'
const Test = ()=> {
    const [value, setValue] = useState(0);
    const [count, setCount] = useState(1);
    const getDoubleCount = useMemo(() => {
        console.log('getDoubleCount进行计算了');
        return count * 2;
    },[count]);
    return (
        <div>
            <h2>value: {value}</h2>
            <h2>doubleCount: {getDoubleCount}</h2>
            <button onClick={() => setValue(value + 1)}>value+1</button>
        </div>
    )
}
export default Test

React Hook用法示例详解(6个常见hook)

现在getDoubleCount只有依赖的count发生变化时才会重新计算渲染。

useMemo和useCallback的共同点:

  • 接收的参数都是一样的,第一个是回调函数,第二个是依赖的数据
  • 它们都是当依赖的数据发生变化时才会重新计算结果,起到了缓存作用

useMemo和useCallback的区别:

  • useMemo计算结果是return回来的值,通常用于缓存计算结果的值
  • useCallback计算结果是一个函数,通常用于缓存函数

6、useRef用法:例如要实现点击button按钮使input输入框获得焦点:

import React, { useState, useMemo } from 'react'
const Test = ()=> {
    const [value, setValue] = useState(0);
    const [count, setCount] = useState(1);
    const getDoubleCount = useMemo(() => {
        console.log('getDoubleCount进行计算了');
        return count * 2;
    },[count]);
    return (
        <div>
            <h2>value: {value}</h2>
            <h2>doubleCount: {getDoubleCount}</h2>
            <button onClick={() => setValue(value + 1)}>value+1</button>
        </div>
    )
}
export default Test

这样看起来非常像React.createRef(),将上面代码中的useRef()改成React.createRef()也能实现同样的效果,那为什么要设计一个新的hook?难道只是会了加上use,统一hook规范?
事实上,它们确实不一样。

官网的说明如下:

useRef returns a mutable ref object whose .current property is initialized to the passed
argument (initialValue). The returned object will persist for the full lifetime of the component.

翻译:

React Hook用法示例详解(6个常见hook)

简单来说,useRef就像一个储物箱,你可以随意存放任何东西,再次渲染时它会去储物箱找,createRef每次渲染都会返回一个新的引用,而useRef每次都会返回相同的引用。

到此这篇关于React Hook用法详解(6个常见hook)的文章就介绍到这了,更多相关React Hook用法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js判断url是否有效的两种方法
Mar 04 Javascript
基于jquery实现动态竖向柱状条特效
Feb 12 Javascript
基于MVC方式实现三级联动(JavaScript)
Jan 23 Javascript
微信小程序中子页面向父页面传值实例详解
Mar 20 Javascript
Angular 4依赖注入学习教程之组件服务注入(二)
Jun 04 Javascript
vue-cli脚手架引入图片的几种方法总结
Mar 13 Javascript
JS代码实现电脑配置检测功能
Mar 21 Javascript
express默认日志组件morgan的方法
Apr 05 Javascript
vue .sync修饰符的使用详解
Jun 15 Javascript
一个因@click.stop引发的bug的解决
Jan 08 Javascript
JS继承实现方法及优缺点详解
Sep 02 Javascript
详解uniapp的全局变量实现方式
Jan 11 Javascript
vue使用v-model进行跨组件绑定的基本实现方法
为什么node.js不适合大型项目
JavaScript控制台的更多功能
Apr 28 #Javascript
JavaScript使用canvas绘制坐标和线
JS Object构造函数之Object.freeze
Apr 28 #Javascript
关于vue中如何监听数组变化
vue实现简单数据双向绑定
Apr 28 #Vue.js
You might like
如何限制访问者的ip(PHPBB的代码)
2006/10/09 PHP
关于Iframe如何跨域访问Cookie和Session的解决方法
2013/04/15 PHP
smarty内置函数{loteral}、{ldelim}和{rdelim}用法实例
2015/01/22 PHP
分析PHP中单双引号的误区和双引号小隐患
2016/07/19 PHP
php往mysql中批量插入数据实例教程
2018/12/12 PHP
疯掉了,尽然有js写的操作系统
2007/04/23 Javascript
Jquery优化效率 提升性能解决方案
2010/09/06 Javascript
nodejs教程 安装express及配置app.js文件的详细步骤
2013/05/11 NodeJs
Jquery 模拟用户点击超链接或者按钮的方法
2013/10/25 Javascript
js的匿名函数使用介绍
2013/12/11 Javascript
JavaScript link方法入门实例(给字符串加上超链接)
2014/10/17 Javascript
基于JavaScript实现Json数据根据某个字段进行排序
2015/11/24 Javascript
谈谈基于iframe、FormData、FileReader三种无刷新上传文件的方法
2015/12/03 Javascript
javascript定时器取消定时器及优化方法
2017/07/08 Javascript
Vue2.0用 watch 观察 prop 变化(不触发)
2017/09/08 Javascript
Angular数据绑定机制原理
2018/04/17 Javascript
浅谈vuepress 踩坑记
2018/04/18 Javascript
学习jQuery中的noConflict()用法
2018/09/28 jQuery
javascript json字符串到json对象转义问题
2019/01/22 Javascript
python根据日期返回星期几的方法
2015/07/06 Python
python实现简易数码时钟
2021/02/19 Python
Python的赋值、深拷贝与浅拷贝的区别详解
2020/02/12 Python
Python3中的tuple函数知识点讲解
2021/01/03 Python
css3动画效果抖动解决方法
2018/09/03 HTML / CSS
CSS实现圆形放大镜狙击镜效果 只有圆圈里的放大
2012/12/10 HTML / CSS
澳大利亚美容产品及化妆品在线:Activeskin
2020/06/03 全球购物
error和exception有什么区别
2012/10/02 面试题
shell的种类有哪些
2015/04/15 面试题
机械设计制造专业个人求职信
2013/09/25 职场文书
日语翻译个人求职的自我评价
2013/10/14 职场文书
中学教师暑期培训方案
2014/08/27 职场文书
2014年英语教学工作总结
2014/12/17 职场文书
作文评语怎么写
2014/12/25 职场文书
佛光寺导游词
2015/02/10 职场文书
车间统计员岗位职责
2015/04/14 职场文书
关于职业道德的心得体会
2016/01/18 职场文书