开始
虚拟 DOM
每个页面在渲染的时候,在内存中会生成一个对应的对象;当页面发生改变需要重新渲染时,会在内存中重新一个对应的对象;当页面需要重新渲染时,会对比两个对象,找到有差异的地方,页面重新渲染时只去渲染发生了改变的地方
diff 算法
| Diff | 说明 |
|---|---|
| tree diff | 新旧 DOM 树,逐层对比的方式,就叫做 tree diff,每当我们从前到后,把所有层的节点对比完后,必然能够找到那些需要被更新的元素; |
| component diff | 在对比每一层的时候,组件直接的对比叫做 component diff;当对比组件的时候,如果两个组件的类型相同,则暂时认为这个组件不需要被更新,如果组件类型不同,则立即将旧组件移除,新建一个组件,替换到被移除的位置 |
| element diff | 在组件中,每个元素之间也要进行对比,元素级别的对比叫做 element diff; |
| key | 这个属性可以把页面上的 DOM 节点和虚拟 DOM 中的对象做一层关联关系 |
React 项目创建
npm react react-dom -s
import React from 'react'
import ReactDOM from 'react-dom'
react这个包专门来创建React组件、组件生命周期等这些东西 react-dom里面主要封装了和DOM操作相关的包,比如要把组件渲染到页面上 React.cteateElement()方法,用于创建虚拟DOM对象,参数1是字符串类型的参数,表示要创建的元素类型,参数2是一个属性对象,表示要创建的元素类型;参数3从第三个参数的位置开始,后面可以放好多虚拟 DOM 对象,这写参数表示当前元素的子节点
var myDiv = React.createElement('div', { title: 'this is a div', id: 'mydiv' }, '这是一个div')
ReactDOM.render(myDiv, document.getElementById('app'))
jsx 语法
npm i babel-preset-react -D,
然后在.babelrc中添加配置"react"JSX语法本质还是以React.createElement的形式来实现的,并没有直接把用户写的HTML代码渲染到页面上
var myDiv = (
<div title="this is a div" id="mydiv">
这是一个div
</div>
)
ReactDOM.render(myDiv, document.getElementById('app'))
如果要在JSX语法内部书写JS代码,那么必须写到{}内部
var myTitle = 'this is title'
var myDiv = (
<div title={myTitle + 'aaa'} id="mydiv">
这是一个div
</div>
)
在JSX中,如果要为元素添加class属性那必须写成className,因为class在ES6中是一个关键字,label标签的for属性需要替换成htmlfor 在JSX创建DOM的时候,所有的节点必须有唯一的根元素进行包裹,如果没有根节点可以使用<></>幽灵节点替代 jsx支持多行,如需换行,需要用()包裹,防止出Bug 如果要写注释,注释必须放到{}内部
jsx 列表渲染
function App() {
return (
<div className="App">
<ul>
{songs.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
jsx 条件渲染
const flag = true
function App() {
return (
<div className="App">
{/* 条件渲染字符串 */}
{flag ? 'react真有趣' : 'vue真有趣'}
{/* 条件渲染标签/组件 */}
{flag ? <span>this is span</span> : null}
</div>
)
}
jsx 样式处理
import './app.css'
import style from './App.module.less'
const styleObj = {
color: red,
}
function App() {
return (
<div className="App">
<div style={styleObj}>this is a div</div>
<p className={style.title}>title</p>
</div>
)
}
组件
使用ES5构造函数的方式创建组件
function Hello() {
var name = '这是一个组件'
return (
<div>
<p>{name}</p>
</div>
)
}
ReactDOM.render(<Hello></Hello>, document.getElementById('app'))
组件传值
function Hello(props) {
console.log(props.name)
var name = '这是一个组件'
return (
<div>
<p>{name}</p>
</div>
)
}
var age = 18
var obj = {
name: 'zs',
score: 150,
}
ReactDOM.render(<Hello {...obj}></Hello>, document.getElementById('app'))
ES5原型方法Animal.prototype.say=function(){..}ES5静态方法Animal.say=function(){..}ES6使用extends实现继承,extends前面是子类,后面是父类
class Person {
// 在每个class类内部,都有一个 constructor 构造器,如果没有显示定义构造器,那么类内部默认都有个看不见的 constructor
// constructor 的作用,就好比function Person(){ }
//每当,使用 new关键字创建 class 类实例的时候,必然会优先调用 constructor构造器
constructor(name, age) {
this.name = name
this.age = age
}
say() {
console.log('haha')
}
static info = 123
static sayHello() {
console.log('静态方法')
}
}
class Man extends Person {
constructor(name, age, sex) {
//super是父类构造器的引用
super(name, age) //super会帮助调用父类的构造器,创建父类的this,然后将父类的this指向子类的this
this.sex = sex
}
}
let p = new Man('zs', 18)
真正的面向对象语言是由三部分组成:封装、继承、多态
使用ES6创建组件
class Hello extends React.Component {
constructor(props) {
super(props)
this.state = {
msg: '这是hello组件的数据',
}
}
render() {
return (
<div>
<p>这是1个组件</p>
<p>{this.state.msg}</p>
<button onClick={this.changeMsg.bind(this)}>按钮</button>
</div>
)
}
changeMsg() {
console.log(this)
this.setState({ msg: '1111111' })
}
}
export default Hello
// ·········
ReactDOM.render(<Hello></Hello>, document.getElementById('app'))
在constructor函数内部的this.state对象定义组件的私有数据,在任何位置都可以使用this.state.msg的方式获取数据 使用this.setState({})方法修改数据才可以触发视图的更新,让rander函数重新执行 this.setState允许接收第二个参数,为callback函数,可以回去到修改后的数据
this.setState(function (prevState, props) {
return { msg: '123' } }, function () { ..})
事件函数定义是直接定义在一个类中,和render函数、constructor函数平级 使用传统的DOM操作绑定事件,可以直接在标签身上加上事件名称或者获取到DOM元素使用addEventlistener 事件函数内部的this默认是undefind,如果希望this是组件对象,可以将事件函数用箭头函数定义,还可以在绑定事件的时候使用bind(this)将事件处理函数内部this固定
ES6 组件传值
var age =18
ReactDOM.render(<Hello age={age}></Hello>,document.getElementById('app'))
// ········
render() {
return <div>
<p>{this.props.age}</p>
</div>
}
ES5构造函数创建组件为无状态组件,ES6 Class类创建组件为有状态组件。
