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

news/2024/11/27 23:44:17/

系列文章目录

第一章: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 *///函数式的setStatethis.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><buttononClick={() => {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><buttononClick={() => {memoizedCallback();}}>useCallback测试</button><buttononClick={() => {setA(100);}}>更改a的值</button><buttononClick={() => {setB(100);}}>更改b的值</button></div>);
}export default Demo;

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


http://www.ppmy.cn/news/10913.html

相关文章

【寒假每日一题】DAY1.水仙花数

一、题目描述 求0&#xff5e;100000之间的所有“水仙花数”并输出。 什么是水仙花数&#xff1a; “水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和确好等于该数本身&#xff0c;如:153&#xff1d;1^3&#xff0b;5^3&#xff0b;3^3&#xff0c;则153是一个“水…

STM32 TIM PWM高阶操作:刹车及状态约束

STM32 TIM PWM高阶操作&#xff1a;刹车及状态约束 刹车及状态约束是STM32 TIM PWM控制里面比较复杂的一部分&#xff0c;涉及到PWM波形产生前&#xff0c;中&#xff0c;后的管脚状态输出。 这里先引入两个描述&#xff0c;一个是“半高阻”&#xff0c;意思是STM32管脚输出…

vue+xlsx实现表格的导入导出:

文章目录一、vue前端使用xlsx和 xlsx-style 导出excel&#xff0c;并修改样式:1、改造后效果&#xff1a;2、实现&#xff1a;3、引入库xlsx-style4、excelUtil.js文件二、前端xlsx插件怎么设置导出的excel列宽自适应&#xff1f;2-1、效果2-2、效果三、xlsx插件&#xff0c;导…

元年科技2022回顾:奋楫扬帆数字化,转型升级立潮头

当下数字经济无疑以最具创新、辐射力最广泛的经济形态迸发着无限活力&#xff0c;这也意味着数字化转型的浪潮风起云涌。作为数字化转型的主力军&#xff0c;元年科技肩负重任奋楫扬帆&#xff0c;在沧海中勇往直前。 回顾2022年&#xff0c;元年科技在不断走向深入的数字化转…

Vue3——第四章(响应式基础:reactive、ref)

一、用reactive()声明响应式状态 我们可以使用 reactive() 函数创建一个响应式对象或数组&#xff1a; 响应式对象其实是 JavaScript Proxy&#xff0c;其行为表现与一般对象相似。不同之处在于 Vue 能够跟踪对响应式对象属性的访问与更改操作。 要在组件模板中使用响应式状…

【Linux】Linux 项目自动化构建工具 -- make/makefile

&#x1f451;作者主页&#xff1a;进击的安度因 &#x1f3e0;学习社区&#xff1a;进击的安度因&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux 文章目录一、前言二、概念三、demo 实现四、原理与规则1、依赖关系和依赖方法① 感性理解② 深层理解…

计算机网络培训总结

在11月份我参加了这次计算机网络培训&#xff0c;虽然这次计算机网络培训的时间很短&#xff0c;但对我来说受益匪浅,充分认识到了自己在计算机应用与网络方面存在很多不足。培训使我的眼界开阔了、思考问题的角度改变了&#xff0c; 许多疑问得到了解决或者启发。 作为一名信息…

STL空间配置器框架分析

目录 一、空间配置器概念 二、空间配置器的作用 三、内存池技术 四、空间配置器的实现原理 3.1 流程概述 3.2 一级空间配置器 3.3 二级空间配置器 3.3.1 二级空间配置器设计 3.3.2 内存碎片问题 一、空间配置器概念 即为各个容器高效的管理空间(空间的申请与回收)的。…