跳至主要內容

开始

Emilia Zhen大约 5 分钟react

虚拟 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,因为classES6中是一个关键字,label标签的for属性需要替换成htmlforJSX创建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类创建组件为有状态组件。