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

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Spring Boot结成MyBatis-Plus最全配置指南

《SpringBoot结成MyBatis-Plus最全配置指南》本文主要介绍了SpringBoot结成MyBatis-Plus最全配置指南,包括依赖引入、配置数据源、Mapper扫描、基本CRUD操... 目录前言详细操作一.创建项目并引入相关依赖二.配置数据源信息三.编写相关代码查zsRArly询数据库数

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

JavaScript错误处理避坑指南

《JavaScript错误处理避坑指南》JavaScript错误处理是编程过程中不可避免的部分,它涉及到识别、捕获和响应代码运行时可能出现的问题,本文将详细给大家介绍一下JavaScript错误处理的... 目录一、错误类型:三大“杀手”与应对策略1. 语法错误(SyntaxError)2. 运行时错误(R