React(zf9-1)

一、概述

基础知识、核心原理、项目实战

npm i create-react-app -g

create-react-app 项目名称

// 查看版本
create-react-app --version

开发效率

二、JSX

vscode如何支持jsx语法:将文件后缀名改成jsx即可

在ReactDOM.createRoot()的时候,不能直接把html/body作为根容器

1.number/string:值是啥渲染出来就是啥
2.boolean/null/undefined/Symbol/BigInt:渲染的内容是空
3.数组:把数组的每一项都分别拿出来渲染,并不是变为字符串渲染(中间没有逗号)
4.除数组外,其余对象一般都不支持(特殊情况:JSX虚拟dom对象、给元素设置style行内样式)

React.createElement(ele, props, ...children)
1.ele:标签名或组件名
2.props:属性集合(对象),如果没有设置任何属性则值为null
3.children:第三个及以后的参数都是当前元素的子节点

createElement方法执行创建出虚拟dom对象
render:把虚拟dom变为真实dom

for...in:既可以迭代私有的,也可以迭代公有的,只能迭代可枚举、非Symbol类型的属性
Object.getOwnPropertyNames():获取对象非Symbol类型的私有属性(无关是否可枚举)
Object.getOwnPropertySymbols():获取对象Symbol类型的私有属性
Reflect.ownKeys():获取所有的私有属性

当type是一个函数时:
1.把函数执行
2.把虚拟dom中的props作为实参传递给函数
3.接收函数执行的返回结果(即当前组件的虚拟dom对象)
4.基于render把组件返回的虚拟dom变为真实dom

三、组件

1.props

关于对象的规则设置:
Object.freeze(obj):冻结对象(被冻结的对象不能修改、新增、删除成员,不能给成员做劫持)
Object.isFrozen(obj):检测是否被冻结,返回true或false
Object.seal(obj):密封对象(被密封的对象可以修改,但不能新增、删除成员,不能给成员做劫持)
Object.isSealed(obj):检测是否被密封
Object.preventExtensions(obj):把对象设置为不可扩展(除了不能新增成员,其余的操作都可以)
Object.isExtensible(obj):检测是否可扩展

// 设置默认值(函数组件)
MyComponent.defaultProps = {
    count: 0
}


import PropTypes from 'prop-types'
// 设置其他规则(数据值格式、是否必传...)
MyComponent.propTypes = {
    title: PropTypes.string.isRequired
}

2.class

class Person {
    // new的时候执行的构造函数
    // 需要接收传递进来的实参才需要设置constructor
    constructor(x, y) {
        // this:创建的实例
        this.total = x + y
    }
    num = 1 // 等价于this.num = 1 给实例设置私有属性
    // 私有的方法
    getNum1 = function () { }
    // 私有的方法
    getNum2 = () => {
        console.log(this) // this:当前创建的实例
    }
    // 公共的方法(原型上的)
    getCount() { }
    // 把构造函数当做一个普通对象,设置静态的私有属性方法
    static sum = 100
    // 把构造函数当做一个普通对象,设置静态的私有属性方法
    static getSum() { }
}
// 设置公共的属性
Person.prototype.count = 1

// 基于extends实现继承
// 1.首先基于call继承:React.Component.call(this) // this:Person类的实例p
// 2.再基于原型继承:Person.prototype.__proto__ === React.Component.prototype
// 实例->Person.prototype->React.Component.prototype->Object.prototype
class Person extends React.Component {
    constructor() {
        // 只要设置了constructor,则内部第一句话一定要执行super()
        // 如果没有设置constructor,则内部默认加了constructor() {super()}
        super()
    }
}

let p = new Person()

3.类组件

import PropTypes from 'prop-types'

class MyComponent extends React.Component {
    // 属性规则校验
    static defaultProps = {
        count: 0
    }
    // 其他规则
    static propTypes = {}
    constructor() {
        super()
    }
}

// 在constructor处理完毕之后,react内部会把传递的props挂载到实例上,所以在其他的函数中只要保证this是实例,就可以基于this.props获取传递的属性

this.forceUpdate():强制更新(会跳过shouldComponentUpdate函数的校验)

4.PureComponent

Object.is(NaN, NaN)是相等的

PureComponent会给类组件默认加一个shouldComponentUpdate,在函数中它会对新旧属性和状态做一个浅比较(只比较第一层),如果没有改变则返回false

5.ref

class MyComponent extends React.Component {
    box3 = React.createRef()
    componentDidMount() {
        console.log(this.refs.box1)
        console.log(this.box2)
        console.log(this.box3.current)
    }
    render() {
        return (
            <div>
                <div ref="box1">1</div>
                {/* x是函数的形参,存储的是当前的dom元素 */}
                <div ref={(x) => this.box2 = x}>2</div>
                <div ref={this.box3}>3</div>
            </div>
        )
    }
}

给标签设置ref:获取dom元素
给类组件设置ref:获取组件的实例
给函数组件设置ref直接报错,但是可以配合React.forwardRef实现ref的转发(获取函数组件(子组件)内部的某个元素)

const Child = React.forwardRef(function Child(props, ref) {
    return (
        <button ref={ref}>按钮</button>
    )
})
class Parent extends React.Component {
    componentDidMount() {
        console.log(this.button) // 子组件内部的button按钮
    }
    render() {
        return (
            <Child ref={x => this.button = x} />
        )
    }
}

6.setState

this.setState(partialState, callback)
partialState:支持部分状态更改
callback:在状态更改、视图更新完毕后触发执行(只要执行了setState,callback一定会执行)
1.发生在componentDidUpdate函数之后,componentDidUpdate会在任何状态更改后都触发执行,而回调函数可以在指定状态更新后处理一些事情
2.基于shouldComponentUpdate阻止了状态/视图更新,componentDidUpdate不会执行,但callback回调函数依然会触发执行

在react18中,setState在任何地方执行都是异步的(实现状态的批处理(统一处理))

在当前相同的时间段内,遇到setState会立即放入到更新队列中

flushSync:可以刷新updater更新队列,即让修改状态的任务立即批处理一次(在flushSync操作结束之后会立即刷新更新队列)
import {flushSync} from 'react-dom'
flushSync(() => {
    this.setState({})
})
或
flushSync()

// prevState:存储之前的状态值
this.setState(prevState => {
    // return的对象就是我们想要修改的新状态值
    return {}
})

7.合成事件

class MyComponent extends React.Component {
    handleClick1() {
        console.log(this) // undefined
    }
    // 只要方法经过bind处理了,那么最后一个实参就是传递的合成事件对象
    handleClick2(x, y, e) {
        console.log(this, x, y) // 实例、1、2
        console.log(e)
    }
    handleClick3 = (e) => {
        console.log(this) // 实例
        console.log(e)
    }
    render() {
        return (
            <div>
                <button onClick={this.handleClick1}>button1</button>
                <button onClick={this.handleClick2.bind(this, 1, 2)}>button2</button>
                <button onClick={this.handleClick3}>button3</button>
            </div>
        )
    }
}

合成事件对象中的nativeEvent:可以获取浏览器内置的原生事件对象

window、document、html、body

事件传播机制
捕获阶段:从最外层向最里层逐一查找
目标阶段:事件源
冒泡阶段:从里到外

事件是浏览器赋予元素的默认行为

event.stopPropagation():阻止事件的传播(包含捕获和冒泡)
event.stopImmediatePropagation:阻止事件的传播(当前元素绑定的其他方法,如果还未执行,也不会再执行了(同一级的方法))

event.target:事件源(点击的是谁,谁就是事件源)

事件委托的好处:提高JS代码运行的性能、给动态绑定的元素做事件绑定
限制:当前操作的事件必须支持冒泡传播机制,例如mouseenter、mouseleave等事件是没有冒泡传播机制的

<div onClick={() => {
    console.log('合成 冒泡')
}} onClickCapture={() => {
    console.log('合成 捕获')
}}></div>

react中合成事件的处理原理:不是给当前元素单独的事件绑定,是基于事件委托处理的
1.在react17以前,都是委托给document容器的,而且只做了冒泡阶段的委托
2.在react17及以后,都是委托给#root这个容器的,捕获和冒泡都做了委托

event.path // path:所有祖先元素(事件源->window)

@珠(zxt)[23]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容