React 原理详解

目录
  • 1.setState() 说明
    • 1.1 更新数据
    • 1.2 推荐语法
    • 1.3 第二个参数
  • 2.JSX 语法的转化过程
  • 3.组件更新机制
  • 4.组件性能优化
    • 4.1 减轻 state
    • 4.2 避免不必要的重新渲染
  • 总结

1.setState() 说明

1.1 更新数据

setState() 是异步更新数据

可以多次调用 setState() ,只会触发一次重新渲染

import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 1,
	}
	handleClick = () => {
		// 异步更新数据
		this.setState({
			count: this.state.count + 1,
		})
        this.setState({
			count: this.state.count + 1,
		})
		console.log(this.state.count) // 1
	}
	render() {
		return (
			<div>
				<h1>计数器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

1.2 推荐语法

使用 setState((state,props)=>{}) 语法

state:表示最新的 state, props:表示最新的 props

import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 1,
	}
	handleClick = () => {
		/* // 异步更新数据
		this.setState({
			count: this.state.count + 1,
		})
		console.log(this.state.count) //1
    this.setState({
			count: this.state.count + 1,
		})
		console.log(this.state.count) //1
    */
		// 推荐语法
		this.setState((state, props) => {
			return {
				count: state.count + 1,
			}
		})
		this.setState((state, props) => {
			console.log('第二次调用:', state) //2
			return {
				count: state.count + 1,
			}
		})
		console.log(this.state.count) // 3
	}
	render() {
		return (
			<div>
				<h1>计数器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

1.3 第二个参数

  • 在状态更新(页面完成重新渲染)后立即执行某个操作
  • 语法:setState(updater[,callback])

callback 是指回调函数 可加可不加

import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 1,
	}
	handleClick = () => {
		this.setState(
			(state, props) => {
				return {
					count: state.count + 1,
				}
			},
			// 状态更新后并且重新渲染后,立即执行
			() => {
				console.log('状态更新完成:', this.state.count) // 2
				console.log(document.getElementById('title').innerText) // 计数器:2
				document.title = '更新后的 count 为:' + this.state.count
			}
		)
		console.log(this.state.count) //1
	}
	render() {
		return (
			<div>
				<h1 id='title'>计数器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

2.JSX 语法的转化过程

  • JSX 仅仅是 createElement() 方法的语法糖(简化语法)
  • JSX 语法被 @babel/preset-react 插件编译为 createElement() 方法
  • React元素:是一个对象,用来描述你希望在屏幕上看到的内容

import React from 'react'
import ReactDOM from 'react-dom'
// JSX 语法的转化过程
// const element = <h1 className='greeting'>Hello JSX</h1>
const element = React.createElement(
	'h1',
	{
		className: 'greeting',
	},
	'Hello JSX'
)
console.log(element)
ReactDOM.render(element, document.getElementById('root'))

3.组件更新机制

  • setState() 的两个作用:1.修改 state 2.更新组件(UI)
  • 过程:父组件重新渲染是,也会重新渲染子组件,但只会渲染当前组件子树(当前组件及其所有子组件)

4.组件性能优化

4.1 减轻 state

  • 减轻 state :只存储跟组件渲染相关的数据(比如:count /列表数据/ loading 等)
  • 注意:不用渲染的书籍不要放在 state 中(比如定时器 id 等)
  • 需要在多个方法中用到的数据,应该放在 this 中

4.2 避免不必要的重新渲染

  • 组件更新机制:父组件更新会引起子组件也被更新
  • 问题:子组件没有变化时也会被重新渲染,造成不必要的重新渲染
  • 解决方式:使用钩子函数shouldComponentUpdate(nextProps,nextState)
  • 作用:通过返回值决定该组件是否重新渲染,返回 true 表示重新渲染, false 表示不重新渲染
  • 触发时机:更新阶段的钩子函数,组件重新渲染前执行(shouldComponentUpdate -> render)
import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 0,
	}
	handleClick = () => {
		this.setState((state) => {
			return {
				count: this.state.count + 1,
			}
		})
	}
	// 钩子函数
	shouldComponentUpdate(nextProps, nextState) {
		// 返回 false,阻止组件重新渲染
		// return false
		// 最新的状态
		console.log('最新的state', nextState)
		// 更新前的状态
		console.log(this.state)
		// 返回 true,组件重新渲染
		return true
	}
	render() {
		console.log('组件更新了')
		return (
			<div>
				<h1>计数器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

案例:随机数

通过 nextState

import React from 'react'
import ReactDOM from 'react-dom'
// 生成随机数
class Opp extends React.Component {
	state = {
		number: 0,
	}
	handleClick = () => {
		this.setState((state) => {
			return {
				number: Math.floor(Math.random() * 3),
			}
		})
	}
	// 两次生成的随机数可能相同,则没必要重新渲染
	shouldComponentUpdate(nextState) {
		console.log('最新状态:', nextState, '当前状态:', this.state)
		return nextState.number !== this.state.number
		/* if ( nextState.number !== this.state.number) {
			return true
		}
		return false*/
	}
	render() {
		console.log('render')
		return (
			<div>
				<h1>随机数:{this.state.number}</h1>
				<button onClick={this.handleClick}>重新生成</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

通过 nextState

import React from 'react'
import ReactDOM from 'react-dom'
// 生成随机数
class Opp extends React.Component {
	state = {
		number: 0,
	}
	handleClick = () => {
		this.setState((state) => {
			return {
				number: Math.floor(Math.random() * 3),
			}
		})
	}
	render() {
		return (
			<div>
				<NumberBox number={this.state.number} />
				<button onClick={this.handleClick}>重新生成</button>
			</div>
		)
	}
}
class NumberBox extends React.Component {
	shouldComponentUpdate(nextProps) {
		console.log('最新props:', nextProps, '当前props:', this.props)
		return nextProps.number !== this.props.number
	}
	render() {
		console.log('子组件render')
		return <h1>随机数:{this.props.number}</h1>
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解关于react-redux中的connect用法介绍及原理解析

    关于react-redux的一个流程图 流程图 connect用法介绍 connect方法声明: connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options]) 作用:连接React组件与 Redux store. 参数说明: mapStateToProps(state, ownProps) : stateProps 这个函数允许我们将 store 中的数据作为 props 绑定到组件上. const mapSta

  • React-router 4 按需加载的实现方式及原理详解

    React-router 4 介绍了在router4以后,如何去实现按需加载Component,在router4以前,我们是使用getComponent的的方式来实现按需加载的,router4中,getComponent方法已经被移除,下面就介绍一下react-router4是入围和来实现按需加载的. 1.router3的按需加载方式 route3中实现按需加载只需要按照下面代码的方式实现就可以了. const about = (location, cb) => { require.ensure

  • 详解React Fiber的工作原理

    啥是React Fiber? React Fiber,简单来说就是一个从React v16开始引入的新协调引擎,用来实现Virtual DOM的增量渲染. 说人话:就是一种能让React视图更新过程变得更加流畅顺滑的处理手法. 我们都知道:进程大,线程小.而Fiber(纤维)是一种比线程还要细粒度的处理机制.从这个单词也可以猜测:React Fiber会很"细".到底怎么个细法,我们接着往下看. 为什么会有React Fiber? 之前说了,React Fiber是为了让React的视

  • ES6 class类链式继承,实例化及react super(props)原理详解

    本文实例讲述了ES6 class类链式继承,实例化及react super(props)原理.分享给大家供大家参考,具体如下: class定义类是es6提供的新的api,比较直观,class类继承也有着一定的规律性,在egg, webpack等库的源码中有着很多的应用场景.结合一些初学者可能遇到的难点,本文主要对其链式继承进行总结,关于super关键字的使用请参考我的其他文章es6中super关键字的理解. class定义 class App { constructor(options){ su

  • React 原理详解

    目录 1.setState() 说明 1.1 更新数据 1.2 推荐语法 1.3 第二个参数 2.JSX 语法的转化过程 3.组件更新机制 4.组件性能优化 4.1 减轻 state 4.2 避免不必要的重新渲染 总结 1.setState() 说明 1.1 更新数据 setState() 是异步更新数据 可以多次调用 setState() ,只会触发一次重新渲染 import React from 'react' import ReactDOM from 'react-dom' class O

  • React Context源码实现原理详解

    目录 什么是 Context Context 使用示例 createContext Context 的设计非常特别 useContext useContext 相关源码 debugger 查看调用栈 什么是 Context 目前来看 Context 是一个非常强大但是很多时候不会直接使用的 api.大多数项目不会直接使用 createContext 然后向下面传递数据,而是采用第三方库(react-redux). 想想项目中是不是经常会用到 @connect(...)(Comp) 以及 <Pro

  • React为什么需要Scheduler调度器原理详解

    目录 正文 我们为什么需要Scheduler(调度器) Scheduler如何进行工作 总结 正文 最近在重学React,由于近两年没使用React突然重学发现一些很有意思的概念,首先便是React的Scheduler(调度器) 由于我对React的概念还停留在React 15之前(就是那个没有hooks的年代),所以接触Scheduler(调度器) 让我感觉很有意思: 在我印象中React的架构分为两层(React 16 之前) Reconciler(协调器)—— 负责找出变化的组件 Rend

  • JavaScript面试Module Federation实现原理详解

    目录 基本概念 1.什么是 Module Federation? 2.Module Federation核心概念 3.使用案例 4.插件配置 工作原理 1.使用MF后在构建上有什么不同? 2.如何加载远程模块? 3.如何共享依赖? 应用场景 1.代码共享 2.公共依赖 总结 基本概念 1.什么是 Module Federation? 首先看一下官方给出的解释: Multiple separate builds should form a single application. These sep

  • 一篇Vue、React重点详解大全

    目录 Vue 生命周期 MVVM 双向绑定原理 虚拟dom v-for为什么要用key nextTick v-show.v-if的区别 vue单页面应用如何首页优化 Vue 的父组件和子组件生命周期钩子执行顺序是什么 Vue 中的 computed 是如何实现的 React 不同之处 vue和react的区别 Vue 生命周期 vue2: 总共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后. 创建前/后: 在beforeCreate阶段,由于还未初始化,vue实例的挂载元素el和数

  • Spring AOP的实现原理详解及实例

    Spring AOP的实现原理详解及实例 spring 实现AOP是依赖JDK动态代理和CGLIB代理实现的. 以下是JDK动态代理和CGLIB代理简单介绍 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理. CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类.CGLIB是高效的代码生成包,底层是依靠ASM(开源的Java字节码编辑类库)操作字节码实现的,性能比JDK强. 在Spring中

  • MySQL prepare原理详解

    Prepare的好处  Prepare SQL产生的原因.首先从mysql服务器执行sql的过程开始讲起,SQL执行过程包括以下阶段 词法分析->语法分析->语义分析->执行计划优化->执行.词法分析->语法分析这两个阶段我们称之为硬解析.词法分析识别sql中每个词,语法分析解析SQL语句是否符合sql语法,并得到一棵语法树(Lex).对于只是参数不同,其他均相同的sql,它们执行时间不同但硬解析的时间是相同的.而同一SQL随着查询数据的变化,多次查询执行时间可能不同,但硬解

  • 前端开发之CSS原理详解

    前端开发之CSS原理详解 从事Web前端开发的人都与CSS打交道很多,有的人也许不知道CSS是怎么去工作的,写出来的CSS浏览器是怎么样去解析的呢?当这个成为我们提高CSS水平的一个瓶颈时,是否应该多了解一下呢? 一.浏览器的发展与CSS 网页浏览器主要通过 HTTP 协议连接网页服务器而取得网页, HTTP 容许网页浏览器送交资料到网页服务器并且获取网页.目前最常用的 HTTP 是 HTTP/1.1,这个协议在 RFC2616 中被完整定义.HTTP/1.1 有其一套 Internet Exp

  • PHP实现链式操作的原理详解

    在一个类中有多个方法,当你实例化这个类,并调用方法时只能一个一个调用,类似: db.php <?php class db { public function where() { //code here } public function order() { //code here } public function limit() { //code here } } index.php <?php $db = new db(); $db->where(); $db->order()

  • Spring IOC原理详解

    最近,买了本Spring入门书:springInAction.大致浏览了下感觉还不错.就是入门了点.Manning的书还是不错的,我虽然不像哪些只看Manning书的人那样专注于Manning,但怀着崇敬的心情和激情通览了一遍.又一次接受了IOC.DI.AOP等Spring核心概念.先就IOC和DI谈一点我的看法. IOC(DI):其实这个Spring架构核心的概念没有这么复杂,更不像有些书上描述的那样晦涩.java程序员都知道:java程序中的每个业务逻辑至少需要两个或以上的对象来协作完成,通

随机推荐