React相关扩展一(setState、lazyLoad、Hooks相关)(九)

news2024/11/16 9:25:07

系列文章目录

第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)
第四章:React脚手架应用(创建脚手架、代理配置、ajax相关、组件通信)(四)
第五章:react-router5路由相关一(路由相关概念、基本使用、NavLink与NavLink的封装、Switch的使用、严格匹配、路由重定向、路由组件与一般组件的区别)(五)
第六章:react-router5路由相关二(嵌套路由、路由传参、replace、编程式路由导航、withRouter的使用、BrowserRouter与HashRouter的区别)(六)
第七章:React-Router6路由相关一(路由的基本使用、重定向、NavLink·、路由表、嵌套路由)(七)
第八章:React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)
第九章:React相关扩展一(setState、lazyLoad、Hooks相关)(九)


文章目录

  • 系列文章目录
    • 一、 setState
      • 1.1 setState更新状态的2种写法
    • 二、 lazyLoad
      • 2.1 路由组件的lazyLoad
    • 三、Hooks
      • 3.1 React Hook/Hooks是什么?
      • 3.2 使用规则
      • 3.3 三个常用的Hook
        • 3.3.1 State Hook
        • 3.3.2 Effect Hook
        • 3.3.3 Ref Hook
      • 3.4 其他Hook
        • 3.4.1 useLayoutEffect(同步执行副作用)
        • 3.4.2 useMemo(记忆组件)
        • 3.4.3 useCallback(记忆函数)


一、 setState

1.1 setState更新状态的2种写法

  • setState(stateChange, [callback])------对象式的setState

    • stateChange状态改变对象(该对象可以体现出状态的更改)
    • callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
  • setState(updater, [callback])------函数式的setState

    • updater返回stateChange对象的函数,updater可以接收到state和props

    • callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用

代码案例:
Demo.jsx

import React, { Component } from 'react'

export default class Demo extends Component {

	state = { count: 0 }

	add = () => {
		//对象式的setState
		/* //1.获取原来的count值
		const {count} = this.state
		//2.更新状态
		this.setState({count:count+1},()=>{
			console.log(this.state.count);
		})
		//console.log('12行的输出',this.state.count); //0 */

		//函数式的setState
		this.setState((state, props) => ({ count: state.count + props.a }), () => {
			console.log('render后输出:', this.state.count);
		})
		console.log('render前输出:', this.state.count);
	}

	render () {
		return (
			<div>
				<h1>当前求和为:{this.state.count}</h1>
				<button onClick={this.add}>点我增加</button>
			</div>
		)
	}
}

App.js

import React, { Component, Fragment } from 'react'
import Demo from './components/1_setState'

export default class App extends Component {
	render () {
		return (
			<div>
				<Demo a={2} />
			</div>
		)
	}
}

运行结果:
在这里插入图片描述

总结:
1.对象式的setState是函数式的setState的简写方式(语法糖)

2.使用原则:

  • 如果新状态不依赖于原状态 ===> 使用对象方式
  • 如果新状态依赖于原状态 ===> 使用函数方式
  • 如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取

二、 lazyLoad

2.1 路由组件的lazyLoad

使路由组件用时再加载

	//1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
	const Login = lazy(()=>import('@/pages/Login'))
	
	//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
	<Suspense fallback={<h1>loading.....</h1>}>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
    </Suspense>

代码案例片段:

Demo.jsx

import React, { Component,lazy,Suspense} from 'react'
import {NavLink,Route} from 'react-router-dom'

// import Home from './Home'
// import About from './About'

import Loading from './Loading'
const Home = lazy(()=> import('./Home') )
const About = lazy(()=> import('./About'))

export default class Demo extends Component {
	render() {
		return (
			<div>
				<div className="row">
					<div className="col-xs-offset-2 col-xs-8">
						<div className="page-header"><h2>React Router Demo</h2></div>
					</div>
				</div>
				<div className="row">
					<div className="col-xs-2 col-xs-offset-2">
						<div className="list-group">
							{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
							<NavLink className="list-group-item" to="/about">About</NavLink>
							<NavLink className="list-group-item" to="/home">Home</NavLink>
						</div>
					</div>
					<div className="col-xs-6">
						<div className="panel">
							<div className="panel-body">
								<Suspense fallback={<Loading/>}>
									{/* 注册路由 */}
									<Route path="/about" component={About}/>
									<Route path="/home" component={Home}/>
								</Suspense>
							</div>
						</div>
					</div>
				</div>
			</div>
		)
	}
}

Loading.jsx

import React, { Component } from 'react'

export default class Loading extends Component {
	render() {
		return (
			<div>
				<h1 style={{backgroundColor:'gray',color:'orange'}}>Loading....</h1>
			</div>
		)
	}
}

Home.jsx

import React, { Component } from 'react'

export default class Home extends Component {
	render() {
		return (
			<h2>我是Home组件</h2>
		)
	}
}

About.jsx
同Home.jsx

运行结果:

在这里插入图片描述


三、Hooks

3.1 React Hook/Hooks是什么?

(1) Hook是React 16.8.0版本增加的新特性/新语法
(2) 可以让你在函数组件中使用 state 以及其他的 React特性
(3) Hook是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用—— 这使得你不使用 class 也能使用 React。可以在新组件中慢慢使用Hook。

3.2 使用规则

Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:

  • 只能在函数最外层调用 Hook。 不要在循环、条件判断或者子函数中调用。
  • 只能在 React 的函数组件中调用 Hook。 不要在其他普通 JavaScript 函数中调用。

3.3 三个常用的Hook

(1). State Hook: React.useState()
(2). Effect Hook: React.useEffect()
(3). Ref Hook: React.useRef()

3.3.1 State Hook

(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)
(3). useState()说明:

  • 参数: 第一次初始化指定的值在内部作缓存
  • 返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数

(4). setXxx()2种写法:

  • setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值

  • setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值

代码案例:

函数式组件写法

function Demo () {
	//console.log('Demo');

	const [count, setCount] = React.useState(0)

	//加的回调
	function add () {
		//setCount(count+1) //第一种写法
		setCount(count => count + 1)
	}

	return (
		<div>
			<h2>当前求和为:{count}</h2>
			<button onClick={add}>点我+1</button>
		</div>
	)
}

export default Demo

类式组件写法

import React from 'react'
import ReactDOM from 'react-dom'

class Demo extends React.Component {

	state = {count:0}

	add = ()=>{
		this.setState(state => ({count:state.count+1}))
	}

	render() {
		return (
			<div>
				<h2>当前求和为{this.state.count}</h2>
				<button onClick={this.add}>点我+1</button>
			</div>
		)
	}
}

运行结果:
在这里插入图片描述

3.3.2 Effect Hook

(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)

(2). React中的副作用操作:

  • 发ajax请求数据获取

  • 设置订阅 / 启动定时器

  • 手动更改真实DOM

(3). 语法和说明:

  useEffect(() => { 
          // 在此可以执行任何带副作用操作
          return () => { // 在组件卸载前执行
            // 在此做一些收尾工作, 比如清除定时器/取消订阅等
          }
        }, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行

useEffect这个函数可以接收两个参数,第一个为函数;第二个为数组(可省略)。对于第二个参数, 如果你传入了一个空数组( [] ),effect 内部的 props 和 state 就会一直持有其初始值。可以向数组中添加需要监听的state,当该state发生变化会引起useEffect重新执行。useEffect 在 渲染时是异步执行,并且要等到浏览器将所有变化渲染到屏幕后才会被执行。跟 useState 一样,你可以在组件中多次使用 useEffect

(4). 可以把 useEffect Hook 看做如下三个函数的组合

  • componentDidMount()

  • componentDidUpdate()

  • componentWillUnmount()

代码片段案例:
函数式组件写法

function Demo () {
	const [count, setCount] = React.useState(0)

	React.useEffect(() => {
		console.log(count)
		let timer = setInterval(() => {
			add()
		}, 1000)
		return () => {
			clearInterval(timer)
		}
	}, [count])

	//加的回调
	function add () {
		//setCount(count+1) //第一种写法
		setCount(count => count + 1)
	}

	//卸载组件的回调
	function unmount () {
		ReactDOM.unmountComponentAtNode(document.getElementById('root'))
	}

	return (
		<div>
			<h2>当前求和为:{count}</h2>
			<button onClick={add}>点我+1</button>
			<button onClick={unmount}>卸载组件</button>
		</div>
	)
}

export default Demo

类式组件写法(运行结果同函数式组件的写法)

import React from 'react'
import ReactDOM from 'react-dom'

class Demo extends React.Component {

	state = {count:0}

	add = ()=>{
		this.setState(state => ({count:state.count+1}))
	}

	unmount = ()=>{
		ReactDOM.unmountComponentAtNode(document.getElementById('root'))
	}

	componentDidMount(){
		this.timer = setInterval(()=>{
			this.setState( state => ({count:state.count+1}))
		},1000)
	}

	componentWillUnmount(){
		clearInterval(this.timer)
	}

	render() {
		return (
			<div>
				<h2>当前求和为{this.state.count}</h2>
				<button onClick={this.add}>点我+1</button>
				<button onClick={this.unmount}>卸载组件</button>
			</div>
		)
	}
} 

运行结果:
在这里插入图片描述

3.3.3 Ref Hook

(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用: 保存标签对象,功能与React.createRef()一样,useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref对象在组件的整个生命周期内持续存在。

代码片段案例:

函数式组件写法

function Demo () {
	const myRef = React.useRef()

	// //提示输入的回调
	function show () {
		alert(myRef.current.value)
	}
	return (
		<div>
			<input type="text" ref={myRef} />
			<button onClick={show}>点我提示数据</button>
		</div>
	)
}

export default Demo

类式组件写法


import React from 'react'
import ReactDOM from 'react-dom'

//类式组件
class Demo extends React.Component {
	myRef = React.createRef()
	
	show = ()=>{
		alert(this.myRef.current.value)
	}
	render() {
		return (
			<div>
				<input type="text" ref={this.myRef}/>
				<button onClick={this.show}>点击提示数据</button>
			</div>
		)
	}
}

运行结果:

在这里插入图片描述


3.4 其他Hook

3.4.1 useLayoutEffect(同步执行副作用)

  • useLayoutEffect其函数签名与useEffect相同,其调用时机和原来的componentDidMount、componentDidUpdate 一致,它会在所有的DOM变更之后同步调用effect。可以使用它来读取 DOM 布局并同步触发重渲染
  • 与useEffect的差异
  • 在浏览器执行绘制之前, useLayoutEffect内部的更新计划将被同步刷新,会阻塞页面渲染。而useEffect是会在整个页面渲染完才会调用的代码,是异步执行的,尽可能使用标准的useEffect以避免阻塞视觉更新。
  • useEffect 的执行时机是浏览器完成渲染之后,而 useLayoutEffect 的执行时机是浏览器把内容真正渲染到界面之前,和componentDidMount 等价。

在实际使用时如果想避免页面抖动(在useEffect 里修改DOM很有可能出现)的话,可以把需要操作DOM的代码放在useLayoutEffect 里。

案例对比效果不明显,暂无案例

3.4.2 useMemo(记忆组件)

useMemo(() => fn, deps)相当于useCallback(fn, deps)返回一个 memoized 值

  • 把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算
    memoized
    。这种优化有助于避免在每次渲染时都进行高开销的计算。
  • 传入useMemo的函数会在渲染期间执行。请不要在这个函数内部执行不应该在渲染期间内执行的操作,诸如副作用这类的操作属于 useEffect的适用范畴,而不是useMemo
  • 如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

代码案例:

import React, { useState, useMemo } from "react";

function Demo() {
  const [num, setNum] = useState(0);
  const [result, setResult] = useState(0);
  let total = useMemo(() => {
    console.log("computed...", Math.random());
    setResult(result + num);
    return result;
  }, [num]);
  return (
    <div>
      <h2>计数器</h2>
      <div>上次结果 : {total}</div>
      <div>本次结果 : {result}</div>
      <div>num : {num}</div>
      <div>
        <button
          onClick={() => {
            setNum(num + 1);
          }}
        >
          change
        </button>
      </div>
    </div>
  );
}

export default Demo;

运行结果:
在这里插入图片描述

与useEffect有点类似,只有useMemo中的第二个参数数组内变量发生变化的时候,才会去重新执行expensive方法。其功能类似vue中的计算属性。

3.4.3 useCallback(记忆函数)

防止因为组件重新渲染,导致方法被重新创建,起到缓存的作用,只有第二个参数变化了,才重新声明一次。

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)返回一个 memoized 回调函数。

  • 把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized
    版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染。

(例如 shouldComponentUpdate)的子组件时,它将非常有用。

代码案例:

import React, { useState, useCallback } from "react";

function Demo() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const memoizedCallback = useCallback(() => {
    // doSomething(a, b);
    console.log(a, b);
  }, [a, b]);
  // 只有a,b改变了才会重新声明该函数
  // 如果传入空数组,在第一次创建后被缓存,如果a,b改变了,获取的是旧值
  // 如果没有传第二个参数,那么每次都会重新声明该函数,拿的是新值
  return (
    <div>
      <button
        onClick={() => {
          memoizedCallback();
        }}
      >
        useCallback测试
      </button>
      <button
        onClick={() => {
          setA(100);
        }}
      >
        更改a的值
      </button>
      <button
        onClick={() => {
          setB(100);
        }}
      >
        更改b的值
      </button>
    </div>
  );
}

export default Demo;

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/150844.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于轻量级CNN的WHDLD多标签遥感分类识别系统

WHDLD数据成像波段包括R、G、B波段&#xff0c;数据覆盖包括6类地貌&#xff1a;裸地、建筑物、人行道、道路、植被、水域。数据集中包含4940张遥感影像及对应地物分类标记样本&#xff0c;影像大小为256x256像素&#xff0c;影像以jpg格式存储&#xff0c;标签数据格式为单通道…

高级前端常考手写面试题合集

解析 URL Params 为对象 let url http://www.domain.com/?useranonymous&id123&id456&city%E5%8C%97%E4%BA%AC&enabled; parseParam(url) /* 结果 { user: anonymous,id: [ 123, 456 ], // 重复出现的 key 要组装成数组&#xff0c;能被转成数字的就转成数字…

React(coderwhy)- 09(项目实战 - 1)

创建React项目 ◼ 创建项目的方式&#xff1a;create-react-app ◼ 项目配置:  配置项目的icon  配置项目的标题  配置jsconfig.json 新建jsconfig.json文件&#xff0c;在文件中粘贴以下内容{"compilerOptions": {"target": "es5","…

【数据结构趣味多】循环队列

目录 函数介绍及模拟实现 Front()函数 Rear()函数 enQueue()函数 deQueue()函数 isEmpty()函数 isFull()函数 循环队列模拟题 定义&#xff1a;把队列的头尾相连接的的顺序存储结构称为循环队列&#xff1b;循环队列的是由顺序表实现的。 为什么要使用循环队列&#…

Android MVVM之SavedStateHandle数据保存之详解与使用。

一、介绍 SavedStateHandle从名字可以看出&#xff0c;是保存状态的。这个类常和MVVM中的ViewModel搭配使用&#xff0c;对页面生命周期的数据状态的缓存与恢复做一个容器。这个容易相对onSaveInstanceState(Bundle)要更强一点&#xff0c;保存的数据类型也比较丰富&#xff0c…

算法刷题打卡第60天:回文链表

回文链表 难度&#xff1a;简单 给定一个链表的 头节点 head &#xff0c;请判断其是否为回文链表。 如果一个链表是回文&#xff0c;那么链表节点序列从前往后看和从后往前看是相同的。 示例 1&#xff1a; 输入: head [1,2,3,3,2,1] 输出: true示例 2&#xff1a; 输入:…

文本摘要,基于Pytorch和Hugging Face Transformers构建示例,有源码

​ 文本摘要的常见问题和解决方法概述&#xff0c;以及使用Hugging Face Transformers库构建基于新浪微博数据集的文本摘要示例。 作 者丨程旭源 学习笔记 1 前言简介 文本摘要旨在将文本或文本集合转换为包含关键信息的简短文本。主流方法有两种类型&#xff0c;抽取式和生…

Nodejs模块的封装(数据库Mysql)

文章目录项目结构本次演示需要使用的第三方包为1.app.js相关配置2.router下的user.js相关配置3.db/index.js文件相关操作4.router_handler下的user.js相关操作项目结构 后面的项目相关文件的创建步骤按照我写的博客从上往下一步一步来 本次演示需要使用的第三方包为 "cor…

【操作系统实验/Golang】实验4:虚拟内存页面置换算法

目录 1 实验问题描述 2 测试数据 3 流程图 4 实验结果 4 实验代码 1 实验问题描述 设计程序模拟先进先出FIFO&#xff0c;最佳置换OPT和最近最久未使用LRU页面置换算法的工作过程。 假设内存中分配给每个进程的最小物理块数为m&#xff0c;在进程运行过程中要访问的页面个…

【Leetcode面试常见题目题解】1. 两数相加

题目描述 本文是leetcode第2题的题解&#xff0c;题目描述摘自leetcode。如下 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个…

海外服务器提供商选择中存在哪些风险?

开展海外业务时&#xff0c;毫无疑问&#xff0c;选择一个高质量的海外服务器提供商可以省去不少麻烦。但是&#xff0c;同时有一些海外服务商需要避开。毕竟一个服务器不靠谱&#xff0c;这跟提供商有很大的原因。下面主要是关于低于标准的海外服务器提供商的一些潜在风险。 1…

ES6中字符串和数组新增的方法

ES6中字符串和数组新增的方法一、字符串中新增的方法1、模板字符串 (表达式、函数的调用、变量)2、repeat(次数)函数 : 将目标字符串重复N次&#xff0c;返回一个新的字符串&#xff0c;不影响目标字符串3、includes()函数 :判断字符串中是否含有指定的子字符串&#xff0c;返回…

mysql 8 新旧密码可以同时生效

在MySQL8.0以前版本&#xff0c;给MySQL更改密码&#xff0c;明确写到开发规范中&#xff0c;拒绝更在线更改更密码&#xff0c;因为在8.0以前操作非常麻烦且不太完美。 MySQL 8.0之前的处理方法&#xff1a; 1. 创建一个同样权限的帐号通过 show grants for ‘user_name’1…

通用vue编辑按钮和新建按钮事件逻辑

一、编辑按钮对话框 1.首先先创建一个文件夹page-model&#xff0c;在里面使用elemengt-plus提供的对话框组件el-dialog。 2.在page-model里面去使用之前封装好的form表单&#xff0c;就是之前封装好的搜索组件的hy-form 3.在form组件里面加一个插槽&#xff0c;对应 page-m…

微信小程序:会议OA项目-首页

目录 一、flex布局 Flex布局简介 什么是flex布局&#xff1f; flex属性 flex的属性 二、轮播图组件及mockjs的使用 三、会议OA小程序首页布局 一、flex布局 Flex布局简介 布局的传统解决方案&#xff0c;基于盒状模型&#xff0c;依赖 display属性 position属性 float…

CompletableFuture详解

CompletableFuture详解 概要 RunnableThread虽然提供了多线程的能力但是没有返回值。CallableThread的方法提供多线程和返回值的能力但是在获取返回值的时候会阻塞主线程。 上述的情况只适合不关心返回值&#xff0c;只要提交的Task执行了就可以。另外的就是能够容忍等待。 C…

Java并发容器

一、并发容器总结1、大部分在 java.util.concurrent 包中。ConcurrentHashMap: 线程安全的HashMapCopyOnWriteArrayList: 线程安全的List&#xff0c;在读多写少的场合性能非常好&#xff0c;远远好于Vector.ConcurrentLinkedQueue: 高效的并发队列&#xff0c;使用链表实现。可…

[ 数据结构 ] 平衡二叉树(AVL)--------左旋、右旋、双旋

0 引出 数列{1,2,3,4,5,6}&#xff0c;要求创建一颗二叉排序树(BST), 并分析问题所在 回顾:二叉搜索树 左子树全部为空&#xff0c;从形式上看&#xff0c;更像一个单链表.插入速度没有影响查询速度明显降低(因为需要依次比较), 不能发挥 BST的优势&#xff0c;因为每次还需要…

第四十二章 动态规划——数字三角形模型

第四十二章 动态规划——数字三角形模型一、数字三角形模型1、什么是数字三角形模型二、例题1、AcWing 1015. 摘花生&#xff08;1&#xff09;问题&#xff08;2&#xff09;思路状态表示状态转移循环设计初末状态&#xff08;3&#xff09;代码2、AcWing 1018. 最低通行费&am…

第二章:感知机

文章目录2.1感知机模型2.2感知机策略2.3梯度下降法2.4感知机-原始算法形式2.5感知机-原始算法实例2.6感知机-对偶形式2.7感知机-对偶形式实例2.8感知机算法收敛性证明如下&#xff1a;2.1感知机模型 2.2感知机策略 损失函数非负&#xff0c;策略是选择使其最小的模型参数 2.3梯…