框架原理第 1 / 7 章
React 基础与组件模型
从版本、JSX 和脚手架进入组件化与高级组件开发。
react的特点
- 声明式 UI= f(state),只需要维护数据,UI会自动被更新
- 组件化 拆分成不同颗粒度的组件
- 跨平台 虚拟dom,编译到不同的平台】
React 版本区别
- api区别
const el= document.querySelector("root")
//18之前,
reactDOM.render(<div>hello world</div>,el)
//18 之后
const root = reactDOM.createRoot(el)
root.render(<div>hello world</div>)
类组件
- 类组件继承自React.Component,初始化时要super去调用一下父组件的构造方法
- 在构造函数中使用 this.state 对象中去定义参与UI更新的数据
- 方法绑定,this问题 类方法中的this绑定,会变成undefined
class App extends React.Component {
constructor(){
super()
this.state = {
message = "hello world"
}
// 方法一trick 在构造函数统一绑定this
// this.btnClick = this.btnClick.bind(this)
}
// 方法一 定义类方法,然后使用的时候绑定this
btnClick(){
//这里的this是不一定就是当前的类,取决于其调用方式,
//如果作为一个回调函数给别的函数调用,由于它是类方法,默认开启严格模式,this的值是undefined
// 所以需要绑定this
console.log(this)
}
// 方法二 箭头函数 默认绑定的是定义时的this,也就是当前实例,这个是类的字段
// btnClick = ()=>{
// console.log(this)
//}
//方法三 事件监听时去定义一个箭头函数
render(){
return (
<div>
<h2>{message}</h2>
<button onClick={this.btnClick.bind(this)}></button>
// {/* 方法三 事件监听时去定义一个箭头函数 */}
<button onClick={ (e)=> this.btnClick(e)}></button>
</div>
)
}
}
jsx语法
- jsx基本语法
🍰 提示
jsx是js扩展语法,允许在js里面书写html代码,html in js,把UI界面的描述融合到js中 为什么react选择了jsx? UI和数据逻辑的耦合度非常高,状态和UI密不可分,所以干脆融合一起
- jsx规范
- 顶层只有一个根元素
- 外层用小括号包裹,实现内容换行,提高可读性
- 单标签使用/结尾
- jsx注释, 使用{}内多行注释的方式
<div>
{/*v这是注释 */}
</div>
- jsx插入内容(标签的children,不是属性)
<div>
{/*基本类型字符串、数字、数组、会直接显示 出来*/}
{ }
</div>
<div>
{/*undefined、null、Boolean 类型会被忽略(即使是true)*/}
{ }
</div>
<div>
{/*对象类型不能作为子对象,会直接报错*/}
{ }
</div>
// 表达式、运算符、函数调用都是合法的
- jsx的属性绑定
- 使用{}进行绑定
- 绑定class,使用关键词className
- 属性中支持绑定一个对象,如style中可以使用一个对象来实现不同的样式绑定
脚手架
组件化开发
🏝️ 提示
把大的模块拆分细化成一系列小的组件,分而治之,最终通过组合实现大的模块的功能 函数组件 (Functional Component) 类组件 (Class Component)
- 类组件
组件名称大写字母开头
类组件需要继承自React.Component
类组件必须实现render函数
constructor是可选的,如果有状态需要维护则需要定义this.state对象,使用this.setState方法更新
render函数必须实现,首次渲染以及this.state 或this.props改变时被执行,它可以返回:
React元素
返回一个数组或fragments
字符串或者数值
- 函数组件
- 函数组件没有生命周期
- this不能指向组件实例
- 内部没法保存状态
- 生命周期
- Mount componetDidMount
- Update componetDidUpdate
- Unmount componetWillUnmount

复杂版,should

- 组件间通信,实现方式多样
🎼 提示
- 直接通过属性来通信,子组件通过props来获取,父组件传递一个回调函数给子组件,子组件执行则实现了子组件给父组件传递数据
- 插槽
🍰 提示
- 通过this.props.children来获取传进去的子组件,多个时是数组,单个时就是子组件本身
- 直接通过this.props 的具体属性来传递
- 作用域插槽 --> 使用一个回调函数来作为组件,子组件使用时传入参数
- 非父子通信
🥖 提示
Context 上下文共享 Context.Consumer 可以在函数组件中使用,也可以在类组件中使用,且多个上下文需要·
- setState
🏖️ 提示
- 第一个参数可以是对象,也可以是函数,函数则会回传(state,props)两个参数,可以处理一些逻辑(如递增的情况,需要用这个state,不一定和this.state相同,取决于有没有更新完成),函数要返回一个state对象
- setState是一个异步调用,调用后不会立即执行state合并,设计成异步的原因是1. 合并多个更新再去调用render,保持state和props的一致性
- setState第二个参数是合并后的回调,确保this.state的新的数据
高级组件开发
🎉 提示
class Component使用 pureComponent,内部已经使用shallowEqual比较state和props的浅层是否相同,相同则不更新,不相同则更新 Functional Component则使用 memo去包裹