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 相关文章推荐
通过JAVASCRIPT读取ASP设定的COOKIE
Feb 15 Javascript
在JavaScript中通过URL传递汉字的方法
Apr 09 Javascript
ASP中用Join和Array,可以加快字符连接速度的代码
Aug 22 Javascript
自己整理的一个javascript日期处理函数
Oct 16 Javascript
JS 排序输出实现table行号自增前端动态生成的tr
Aug 13 Javascript
浅谈JavaScript function函数种类
Dec 29 Javascript
基于Node.js的强大爬虫 能直接发布抓取的文章哦
Jan 10 Javascript
老生常谈onBlur事件与onfocus事件(js)
Jul 09 Javascript
jquery动态添加文本并获取值的方法
Oct 12 Javascript
JS控件bootstrap suggest plugin使用方法详解
Mar 25 Javascript
大白话讲解JavaScript的Promise
Apr 06 Javascript
如何实现iframe父子传参通信
Feb 05 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
基于HTTP长连接的&quot;服务器推&quot;技术的php 简易聊天室
2009/10/31 PHP
php 获取当前访问的url文件名的方法小结
2010/02/08 PHP
ThinkPHP中html:list标签用法分析
2016/01/09 PHP
Zend Framework教程之视图组件Zend_View用法详解
2016/03/05 PHP
Yii配置与使用memcached缓存的方法
2016/07/13 PHP
php 函数使用可变数量的参数方法
2017/05/02 PHP
实现变速回到顶部的JavaScript代码
2011/05/09 Javascript
JavaSript中变量的作用域闭包的深入理解
2014/05/12 Javascript
详解js数组的完全随机排列算法
2016/12/16 Javascript
jQuery+HTML5实现弹出创意搜索框层
2016/12/29 Javascript
VUE JS 使用组件实现双向绑定的示例代码
2017/01/10 Javascript
JS实现弹出下载对话框及常见文件类型的下载
2017/07/13 Javascript
详解用函数式编程对JavaScript进行断舍离
2017/09/18 Javascript
详解Vue取消eslint语法限制
2018/08/04 Javascript
Vue将页面导出为图片或者PDF
2020/08/17 Javascript
js实现表单项的全选、反选及删除操作示例
2020/06/05 Javascript
Python中for循环和while循环的基本使用方法
2015/08/21 Python
Python第三方库的安装方法总结
2016/06/06 Python
Python合并字典键值并去除重复元素的实例
2016/12/18 Python
python实现隐马尔科夫模型HMM
2018/03/25 Python
Python不同目录间进行模块调用的实现方法
2019/01/29 Python
python基于FTP实现文件传输相关功能代码实例
2019/09/28 Python
如何搭建pytorch环境的方法步骤
2020/05/06 Python
numpy中生成随机数的几种常用函数(小结)
2020/08/18 Python
Python requests HTTP验证登录实现流程
2020/11/05 Python
中外合拍动画首获奥斯卡提名,“上海出品”《飞奔去月球》能否拿下最终大奖?
2021/03/16 国漫
中软国际Java程序员机试题
2012/08/19 面试题
学校法制宣传月活动总结
2014/07/03 职场文书
小学生运动会通讯稿
2014/09/23 职场文书
乡镇务虚会发言材料
2014/10/20 职场文书
巾帼标兵事迹材料
2014/12/26 职场文书
大一学生个人总结
2015/02/15 职场文书
承兑汇票延期证明
2015/06/23 职场文书
某某店铺的开业庆典主持词范本
2019/11/25 职场文书
Python一行代码实现自动发邮件功能
2021/05/30 Python
解决vue中provide inject的响应式监听
2022/04/19 Vue.js