React Hook 指南 useState() useEffect() useReducer() 自定义 Hook

本文主要是介绍React Hook 指南 useState() useEffect() useReducer() 自定义 Hook,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • useState()状态管理
    • setState 和 useState 的区别
    • setState 和 useState 同样场景的应用
    • 如何让 Function Component 也打印 3 3 3
      • 借助一个新 Hook - useRef 的能力
      • 如何不改造原始值也打印 3 3 3
    • useState() 的无效调用
  • useEffect()状态管理
    • useEfffect第二个参数不能使用引用类型
  • 复杂状态用useReducer
  • 自定义 Hook

useState()状态管理

import React, { usestate } from 'react" ;function Bulbs() {
const [setOn] = useState( false) ; //设置初始值为false
const lightOn= ()=>set0n( true ); //改变初始值
const lightOff =()=> setOn( false );
return (
<div className={on ? 'bulb-on' : 'bulb-off '}/>
<button onclick={lightOn}>开灯</ button>
<button onclick={light0ff}>关灯</button></>
);}

setState 和 useState 的区别

1.获取修改后的值
setState

this.state={
count:0
}
this.setState({count: this.state.this.state=count + 1
}, () => {console.log(this.state.count); // 这里是监控到的最新值
})

useState

const [ count, setCount ] = useState(0);
setCount(1); 
useEffect(() => {console.log(count); // 这里是监控到的最新值
}, [ count ]);

setState 和 useState 同样场景的应用

setState

class Counter extends Component {state = { count: 0 };log = () => {this.setState({count: this.state.count + 1});setTimeout(() => {console.log(this.state.count);}, 3000);};render() {return (<div><p>You clicked {this.state.count} times</p><button onClick={this.log}>Click me</button></div>);}
}
// 3 3 3

首先 state 是 Immutable 的,setState 后一定会生成一个全新的 state 引用。
但 Class Component 通过 this.state 方式读取 state,这导致了每次代码执行都会拿到最新的 state 引用,所以快速点击三次的结果是 3 3 3。

useState

function Counter() {const [count, setCount] = useState(0);const log = () => {setCount(count + 1);setTimeout(() => {console.log(count);}, 3000);};return (<div><p>You clicked {count} times</p><button onClick={log}>Click me</button></div>);
}
// 0 1 2

useState 产生的数据也是 Immutable 的,通过数组第二个参数 Set 一个新值后,原来的值会形成一个新的引用在下次渲染时。
但由于对 state 的读取没有通过 this. 的方式,使得 每次 setTimeout 都读取了当时渲染闭包环境的数据,虽然最新的值跟着最新的渲染变了,但旧的渲染里,状态依然是旧值。

如何让 Function Component 也打印 3 3 3

借助一个新 Hook - useRef 的能力

function Counter() {const count = useRef(0);const log = () => {count.current++;setTimeout(() => {console.log(count.current);}, 3000);};return (<div><p>You clicked {count.current} times</p><button onClick={log}>Click me</button></div>);
}

useRef 的功能:通过 useRef 创建的对象,其值只有一份,而且在所有 Rerender 之间共享。
count.current 赋值或读取,读到的永远是其最新值,而与渲染闭包无关,因此如果快速点击三下,必定会返回 3 3 3 的结果。
但这种方案有个问题,就是使用 useRef 替代了 useState 创建值.

如何不改造原始值也打印 3 3 3

function Counter() {const [count, setCount] = useState(0);const currentCount = useRef(count);useEffect(() => {currentCount.current = count;});const log = () => {setCount(count + 1);setTimeout(() => {console.log(currentCount.current);}, 3000);};return (<div><p>You clicked {count} times</p><button onClick={log}>Click me</button></div>);
}

一种最简单的做法,就是新建一个 useRef 的值给 setTimeout 使用,而程序其余部分还是用原始的 count

useState() 的无效调用

在条件中调用useState()是不正确的:

function Switch({ isSwitchEnabled }) {if (isSwitchEnabled) {// Badconst [on, setOn] = useState(false);}// ...
}

在嵌套函数中调用useState()也是不对的

function Switch( ) {let on = false;let setOn = ( ) => {};function enableSwitch() {[ on,setOn] = usestate(false);}
return (
<button onclick=fenableSwitch}>Enable light switch state
</button>
);
}

useEffect()状态管理

function Counter() {const [count, setCount] = useState(0);const currentCount = useRef(count);useEffect(() => {currentCount.current = count;});const log = () => {setCount(count + 1);setTimeout(() => {console.log(currentCount.current);}, 3000);};return (<div><p>You clicked {count} times</p><button onClick={log}>Click me</button></div>);
}
// 3 3 3

useEffect 会在第一次渲染之后和每次更新之后都会执行。
相当于componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合

useEffect 是处理副作用的,其执行时机在 每次 Render 渲染完毕后,换句话说就是每次渲染都会执行,只是实际在真实 DOM 操作完毕后。
我们可以利用这个特性,在每次渲染完毕后,将 count 此时最新的值赋给 currentCount.current,这样就使 currentCount 的值自动同步了 count 的最新值。

要注意的是,useEffect 也随着每次渲染而不同的,同一个组件不同渲染之间,useEffect
内闭包环境完全独立。对于本次的例子,useEffect 共执行了 四次,经历了如下四次赋值最终变成 3:
setTimeout 的例子,三次点击触发了四次渲染,但 setTimeout 分别生效在第 1、2、3 次渲染中,因此值是 0 1 2。
useEffect 的例子中,三次点击也触发了四次渲染,但 useEffect 分别生效在第 1、2、3、4 次渲染中,最终使 currentCount 的值变成 3。

useEfffect第二个参数不能使用引用类型

useEffect接受两个参数

  • 第一个参数是函数(这里叫effect函数),它的作用是,在页面渲染后执行这个函数。因此你可以把
    ajax请求等放在这里执行;

  • 第二个参数是一个数组,这里注意:
    在这里插入图片描述

import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState({});useEffect(() => {setCount({test:"count是一个对象,使得页面死循环"})},[count]);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}
//死循环

是因为在JavaScript中,{} === {}结果是false,{a:1} === {a:1}同样,由此造成了react以为两个值不同,就一直的渲染最终页面死循环

使用useEffect()时,有一点需要注意。如果有多个副效应,应该调用多个useEffect(),而不应该合并写在一起。

复杂状态用useReducer

用法 => const [state, dispatch] = useReducer(reducer, initialState);

function reducer(state, action) {switch (action.type) {case "increment":return {...state,count: state.count + 1};default:return state;}
}

这样就可以通过调用 dispatch({ type: ‘increment’ }) 的方式实现 count 自增了。

假设需要编写一个最喜欢的电影列表。用户可以添加电影,也可以删除已有的电影
reducer管理电影的状态,有两种操作类型:
"add"将新电影插入列表
"remove"从列表中按索引删除电影

import React, { useReducer } from 'react ' ;function reducer( state,action) {
switch (action.type) {
case 'add ' :
return [...state,action.item];case ' remove ' :
return [
...state.slice( 0,action.index ),...state.slice( action.index + 1)];
default:
throw new Error( );
}
}
function FavoriteMovies( ) {
const [state,dispatch] = useReducer( reducer,[{ name: 'Heat' }]
return (
);

自定义 Hook

是不是觉得每次都写一堆 useEffect 同步数据到 useRef 很烦?是的,想要简化,就需要引出一个新的概念:自定义 Hooks。
首先介绍一下,自定义 Hooks 允许创建自定义 Hook,只要函数名遵循以 use 开头,且返回非 JSX 元素,就是 Hooks 啦!自定义 Hooks 内还可以调用包括内置 Hooks 在内的所有自定义 Hooks。

function useCurrentValue(value) {const ref = useRef(0);useEffect(() => {ref.current = value;}, [value]);return ref;
}

useEffect 的第二个参数,dependences。dependences 这个参数定义了 useEffect 的依赖,在新的渲染中,只要所有依赖项的引用都不发生变化,useEffect 就不会被执行,且当依赖项为 [] 时,useEffect 仅在初始化执行一次,后续的 Rerender 永远也不会被执行。

function Counter() {const [count, setCount] = useState(0);const currentCount = useCurrentValue(count);const log = () => {setCount(count + 1);setTimeout(() => {console.log(currentCount.current);}, 3000);};return (<div><p>You clicked {count} times</p><button onClick={log}>Click me</button></div>);
}
// 3 3 3
//这个例子中,我们告诉 React:仅当 value 的值变化了,再将其最新值同步给 ref.current。

eslint-plugin-react-hooks
这个插件,会自动订正你的代码中的依赖,想不对依赖诚实都不行!

这篇关于React Hook 指南 useState() useEffect() useReducer() 自定义 Hook的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/766531

相关文章

PostgreSQL中rank()窗口函数实用指南与示例

《PostgreSQL中rank()窗口函数实用指南与示例》在数据分析和数据库管理中,经常需要对数据进行排名操作,PostgreSQL提供了强大的窗口函数rank(),可以方便地对结果集中的行进行排名... 目录一、rank()函数简介二、基础示例:部门内员工薪资排名示例数据排名查询三、高级应用示例1. 每

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查

Java操作Word文档的全面指南

《Java操作Word文档的全面指南》在Java开发中,操作Word文档是常见的业务需求,广泛应用于合同生成、报表输出、通知发布、法律文书生成、病历模板填写等场景,本文将全面介绍Java操作Word文... 目录简介段落页头与页脚页码表格图片批注文本框目录图表简介Word编程最重要的类是org.apach

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

Linux中SSH服务配置的全面指南

《Linux中SSH服务配置的全面指南》作为网络安全工程师,SSH(SecureShell)服务的安全配置是我们日常工作中不可忽视的重要环节,本文将从基础配置到高级安全加固,全面解析SSH服务的各项参... 目录概述基础配置详解端口与监听设置主机密钥配置认证机制强化禁用密码认证禁止root直接登录实现双因素