12.27_React_04

React 性能优化

setState()作用: 修改state 更新组件UI

更新机制:

父组件更新时 父组件包含的子组件都会进行更新 子组件包含的组件也会进行更新 只会更新当前父组件包含的当前子组件树

减轻 state:

在state中只存放和组件渲染相关的 需要变动的页面数据

例: 计时器、id等这类数据可以存放在this中

// this可以多个方法直接进行访问 也可以实现数据共享
// 存放时 this.xxx = 当前的变量
this.id = setInterval(() => {}, 200)

// 使用时
clearInterval(this.id)

减少不必要的渲染:

根据更新机制的概念 当子组件没有被改变时也会被更新 这种情况被称为不必要的更新 如何解决这种不必要的更新

解决方法: shouldComponentUpdate(nextProps, nextState)

// 写在类组件中
// render之前触发 返回值是布尔值
// false 不重新渲染
// true 重新渲染

// 使用nextState时
shouldComponentUpdate(nextProps,nextState) {
    if(nextState.xx == this.state.xx){
       return false
    } // 根据判断是否渲染 或三元表达式
    return true
}
render () {...}

// 使用nextProps时
shouldComponentUpdate(nextProps,nextState) {
    if(nextProps.xx == this.state.xx){
       return false
    } // 根据判断是否渲染 或三元表达式
    return true
}
render () {...}

// nextProps 当前最新的props通信传递的值 在需要通过传递的值来作为是否渲染组件的条件时 使用nextProps
// nextState 当前最新的state状态值 在需要通过组件自身内部的state状态值来作为是否渲染组件条件时 使用nextState
// this.state 获取更新前的state状态值

纯组件 PureComponent

作用:内部实现了shouldComponentUpdate钩子函数的功能 不需要手动比较

原理: 内部已经通过对比前后props和前后state的值 来决定是否渲染组件

缺点:只是将props和state的值进行了对比 是浅层对比 一旦对比的是复杂数据类型(引用类型) 会出现问题

// 将class继承中的React.Component替换为React.PureComponent
class NumberBox extends React.PureComponent {
    // 此处不需要shouldComponentUpdate钩子函数了 组件内部自动判断
    render() {
        return {
            <div>要被渲染的内容或组件</div>
        }
    }
}

纯组件弊端

纯组件内部比对是浅层比对 在值对比时没有什么问题 但是在引用对比时 会出现问题 因为对比只是对比了引用的对象(地址) 是否相同 在直接修改了原始对象时 因为前后的对象并没有改变 这种情况下不会重新渲染

class App extends React.PureComponent {
    state = {
        obj: {
            number: 0
        }
    }
	// 事件处理程序
	handleClick = () => {
        // 修改state需要在setState中 
        // 错误示范:直接修改state对象数值中的数值
        const newObj = this.state.obj
        newObj.number = Math.floor(Math.random() * 3)
    }
}

// 解决方法思路 修改原始对象因为修改的前后都是同一个对象 所以不会触发渲染 但是重新原始对象的基础上创建一个对象 修改时因为创建的对象和原始对象并不是同一个地址指向 所以会触发渲染

class App extends React.PureComponent {
    state = {
        obj: {
            number: 0
        }
    }
	// 事件处理程序
	handleClick = () => {
        // 修改state需要在setState中 
        // 错误示范:直接修改state对象数值中的数值
        const newObj = this.state.obj
        newObj.number = Math.floor(Math.random() * 3)
        
        // 正确做法
		const newObj = {...state.obj, number: 2}
        setState({ obj: newObj })
    }
}

// 总结: 在使用引用类型数据时 重新创建一个新的数据 不在原始数据上直接修改
// 注意点: 在使用数组方法时不要使用 push/unshift 直接修改原数组的方法 而应该使用 concat/slice 返回新数组的方法
// 扩展运算符 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
this.setStatae({
    list: [...this.state.list, {新数据}]
})

注:计算属性也是浅层对比 引用类型: 也称之为复杂数据类型

虚拟DOM和diff算法 √

React是如何做到部分更新的: 通过diff算法找前后两次虚拟dom的不同点 再根据不同点进行更新

作用:实现部分更新

虚拟DOM:

虚拟DOM不是真正的DOM元素 是通过state和JSX去描述html结构的一段代码 在浏览器是展示的htmlDOM 结构 在其他平台又是展示的其他结构 是多变的 所以它可以跨平台使用 就是所谓的编写一次多处使用的理念

在这里插入图片描述

diff算法:

作用:寻找到虚拟DOM结构的上一次和这一次不同的地方 只将需要变化的内容进行更新

流程:在初次渲染时 会渲染一个默认的虚拟DOM树 当数据发生变化后 会重新渲染一个虚拟DOM树和上一次的DOM树进行比较 根据比较后得出的变化内容 只将变化的内容和上一次的虚拟DOM进行结合

❤ React 路由

路由是为了实现SPA单页面应用程序能够渲染对应组件的DOM结构产生的 因为SPA单页面 只有一个HTML页面 要展示不同的页面 需要根据一个html页面映射对应的路径和对应的组件来实现功能渲染

作用: 根据配置的路径来跳转到对应的组件 并展示组件渲染的DOM结构

基本使用:

  • 安装:npm i react-router-dom

  • 导入核心组件: import {BrowserRouter as Router, Route, Link} from 'react-router-dom'

  • BrowserRouter as Router 是将名称给更改为了Router 包裹的标签根据更改的名称来决定

  • BrowserRouter: 路由管理器 管理路由的匹配

  • Link: 入口:设置跳转的路径

  • Route: 出口:设置路由的规则 精确匹配设置属性exact

// 使用Router包裹组件中的整个应用 并且只需要使用一次
// Route 组件写在哪 内容就展示在哪 类似于当年的路由占位符
class App extends React.Component {
    <Router>
		<div>
		{/* 入口 = a标签 展示在表面的一个切换组件开关 */}
		<Link to="/url"></Link>
		{/* 出口 = 当启动了切换开关 需要切换到对应组件的规则 */}
        <Route path="/url", component={被展示的组件名称} />
		</div>
	</Router>
}
// 入口标签的to属性又被称为pathname

*路由的执行过程:

当url地址栏中的路径改变时 路由会侦听到变动 会更具改变后的url地址 循环所有设置的路由规则 找到对应的路由规则将对应规则的组件的内容渲染出来

HashRouter 哈希路由

是和BrowserRouter 路由一样功能的另一个路由 展示方法有所不同

Hash路由:localhost:3000/#/url 展示有#链接

* Browser路由:localhost:3000/url 展示没有 推荐

location.pathname 可以拿到浏览器pathname路径地址/url

编程式导航 history

作用: 当用户需要通过点击某个按钮 跳转到对应组件页面

本质:通过js代码来实现页面的跳转

history :是React路由标签提供的 只有在被路由标签包裹的组件才有这个属性 用于获取浏览器历史记录

// 在需要点击跳转页面的类组件中
class Login extends React.Component {
    // 去首页事件处理程序
	route = () => {
        // push('/url'):去往某一个页面
		this.props.history.push('/url')
	}
	
    // 返回上一层事件处理程序
    getgo = () => {
        // go(-1):返回上一层页面
    	this.props.history.go(-1)
	}
	
    render() {
    	return (
        	<div>
            	<button onClick={this.route}>点击去首页</button>
                <button onClick={this.getgo}>返回上一层</button>
            </div>
        )
    }
}
// 为什么是props拿到的history呢 因为当前的Login 是通过另一个组件的路由渲染出来的 在渲染的时候 路由会往组件中存放一些方法 history就是其中之一

*默认路由

作用:打开页面显示的默认组件页面

class App extends React.Component {
    <Router>
		<div>
		{/* 
			出口 = 当启动了切换开关 需要切换到对应组件的规则
        	只需要将path改为 ' / ' 
        */}
        <Route path="/" component={默认显示组件} />
		</div>
	</Router>
}

匹配模式

因为路由的匹配模式是默认的模糊匹配 默认路由是以/开头 然而所有的路由路径开头都以 / 开头 所以默认路由展示的组件会一直展示

模糊匹配

是默认的路由匹配模式 模糊匹配只会匹配开头 当pathname开头和path开头相同就能匹配成功

  • pathname: Link to的开头

  • path:Route path的开头

为什么模糊匹配会是默认匹配模式:为了方便函数封装 不用再次进行导入

造成的问题: 因为默认路径是/ 但是所以路径都是以/ 开头 通过模糊匹配所有的路径都会被匹配成默认路由的页面

精确匹配

是模糊匹配造成问题的解决方法 当path和pathname完全匹配才会展示对应的组件

// 给Route组件添加 exact属性 将模式转换为精确匹配 精确匹配模式并不会只匹配开头 会进行全部对比
class App extends React.Component {
    <Router>
		<div>
		{/* 
			出口 = 当启动了切换开关 需要切换到对应组件的规则
        	只需要将path改为 ' / ' 
        */}
        <Route exact path="/" component={默认显示组件} />
		</div>
	</Router>
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值