准备工作

使用 React 开发者工具调试


复习 相关知识

  • 定义 class(类),代码如下:

    // 创建一个 Person 类
    class Person {// 构造器方法constructor(name, age) {// 构造器中的this是谁? -- 类的实例对象this.name = namethis.age = age}// 一般方法speak() {// speak 方法放在了哪里? -- 类的原型对象上,供实例使用// 通过 Person 实例调用speak时,speak中的this就是Person实例console.log(`我叫${this.name}, 我年龄是${this.age}`);}
    }// 创建一个 person 的实例对象
    const p1 = new Person('tom', 18)
    const p2 = new Person('jerry', 19)console.log(p1);
    console.log(p2);
    p1.speak()
    p2.speak()// p1.speak.call({a: 1, b:2}) // this 指向 {a: 1, b:2}
    
  • extends实现继承,代码如下:

    // 创建一个 Student 类,继承于 Person 类
    class Student extends Person {constructor(name, age, grade) {// 子类必须调用父类的构造器, 必须要在最开始调用super(name, age)this.grade = gradethis.school = '尚硅谷'}// 重写从父类继承的方法speak() {console.log(`我叫${this.name}, 我年龄是${this.age},我读的是${this.grade}年级`);}study() {// study 方法放在了哪里? -- 类的原型对象上,供实例使用// 通过 Student 实例调用study时,study中的this就是Student实例console.log('我很努力的学习');}
    }const s1 = new Student('小张', 15, '高一')
    console.log(s1);
    s1.speak()
    s1.study()
    
  • 类的实例对象添加属性

    class Car {constructor (name, price) {this.name = namethis.price = price// this.wheel = 4}// 类中可以直接写赋值语句,如下代码的含义是,给 Car 的实例对象添加一个属性,名为a,值为1a = 1wheel = 4// 给类本身添加属性,静态属性static demo = 100
    }
    Car.demo = 100
    const c1 = new Car('奔驰c63', 199)
    const c2 = new Car('宝马', 299)
    console.log(c1.demo);
    
  • 总结

    1,类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时才写
    2,如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的
    3,类中所定义的方法,都是放在了类的原型对象上,供实例去使用

基本使用

函数式组件

  • 示例示例要求,如图所示:

  • 语法:定义函数式组件

    // 1. 创建函数式组件,首字母必须大写
    function MyComponent () {console.log(this); // 此处的this是undefined 因为babel编译后开启严格模式return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
    }// 2. 渲染组件到页面
    ReactDOM.render(<MyComponent />, document.getElementById('test'))
    /*** 执行了 ReactDOM.render(<MyComponent />, ......) 之后,发生了什么?、*     1. React 解析组件标签,找到了 MyComponent 组件*     2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中*/
    
  • 注意

    1,创建函数式组件,组件名首字母必须大写
    2,函数式数组,必须有返回值
    3,渲染组件时,必须写成标签的形式,并且要闭合

类式组件

  • 示例示例要求,如图所示:

  • 语法:定义类式组件

    // 1. 创建类式组件
    // 类式组件 需要继承 React.Component(React 的内置组件)
    class MyComponent extends React.Component {render() {// render 是放在哪里的?-- MyComponent的原型对象上,供实例使用// render 中的this是谁? -- MyComponent的实例对象 <=> MyComponen组件实例对象 return  <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>}
    }// 2. 渲染组件到页面
    ReactDOM.render(<MyComponent />, document.getElementById('test'))
    /*** 执行了 ReactDOM.render(<MyComponent />, ......) 之后,发生了什么?、*     1. React 解析组件标签,找到了 MyComponent 组件*     2. 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到原型上的 render 方法*     3. 将 render 返回的虚拟DOM 转为真实DOM,随后呈现在页面中*/
    
  • 注意

    1,类式组件,必须继承 React.Component (React 的内置组件)
    2,类式组件,内部必须重写 render() 函数
    3,类式组件,render() 中必须要有返回值

渲染类组件标签的基本流程

  • 1,React 内部会创建组件实例对象
  • 2,调用 render() 得到 虚拟DOM, 并解析为 真实DOM
  • 3,插入到指定的页面元素内部

注意事项

  • 1,组件名必须首字母大写
  • 2,虚拟DOM元素只能有一个根元素
  • 3,虚拟DOM元素必须有结束标签

组件实例的三大核心属性

state


示例要求

需求:定义一个展示天气信息的组件

  • 1,默认展示天气炎热 或 凉爽

  • 2,点击文字切换天气

基本理解

  • 1,state组件实例对象最重要的属性, 值是对象(可以包含多个 key-value 的组合),类似于 Vue 中的 data
  • 2,组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

案例分析

  • 在构造器 constructor 中,初始化 state

    constructor(props) {super(props)// 初始化状态 statethis.state = { isHot: true, wind: '微风' }
    }
    
  • Weather 组件实例对象的原型对象上,定义方法

    changeWeather() {// .....
    }
    
  • 解决 changeWeather 方法中 this 指向问题

    constructor(props) {......this.changeWeather = this.changeWeather.bind(this)
    }
    
  • 使用 setState 改变 isHot 的值,并重新渲染视图

    changeWeather() {// 读取原来的 isHot 值const isHot = this.state.isHot// 严重注意:状态必须通过 setState 进行更新,且更新是一种合并,不是替换this.setState({ isHot: !isHot })// 严重注意:状态(state) 不可直接更改,下面这行就是直接更改!!!// this.state.isHot = !isHot // 这是错误的方法,只改变 isHot 的值,但并未重新渲染视图
    }
    

基础实现

  • 代码分析,如下所示:

    // 1. 创建组件
    class Weather extends React.Component {// 构造器调用几次?-- 1次constructor(props) {super(props)// 初始化状态 statethis.state = { isHot: true, wind: '微风' }// 解决类中 this 指向问题// bind 生成新的函数,改变 this 指向// 给 Weather 实例对象,添加 changeWeather 方法// 右边的 this.changeWeather 表示 Weather 的原型对象上的 changeWeather 方法this.changeWeather = this.changeWeather.bind(this)}// render 调用几次?-- 1 + n 次,1 是初始化的那次;n 是状态更新的次数render() {// this : Weather 组件实例对象// 读取状态 stateconst { isHot, wind } = this.state// 此处使用的是 Weather 自身的 changeWeather 方法return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}// changeWeather 调用几次?-- 点几次调几次changeWeather() {// changeWeather 放在哪里?-- Weather 的原型对象上,供实例使用                // 由于 changeWeather 是作为 onClick 的回调,所以不是通过实例调用的,是直接调用// 类中的方法默认开启了局部的严格模式,所以 changeWeather 中的 this 为 undefined// 读取原来的 isHot 值const isHot = this.state.isHot// 严重注意:状态必须通过 setState 进行更新,且更新是一种合并,不是替换this.setState({ isHot: !isHot })// 严重注意:状态(state) 不可直接更改,下面这行就是直接更改!!!// this.state.isHot = !isHot // 这是错误的方法}
    }// 2. 渲染组件到页面
    ReactDOM.render(<Weather />, document.getElementById('test'))
    

优化实现

  • 代码分析,如下所示:

    // 1. 创建组件
    class Weather extends React.Component {// 往 Weather 实例对象中添加属性 state// 初始化状态 statestate = { isHot: true, wind: '微风' }render() {const { isHot, wind } = this.statereturn <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}// 自定义方法 -- 要用赋值语句的形式 + 箭头函数// 将其放在 往 Weather 实例对象自身changeWeather = () => {console.log(this); // this 指向 Weather 实例对象const isHot = this.state.isHotthis.setState({ isHot: !isHot })}
    }// 2. 渲染组件到页面
    ReactDOM.render(<Weather />, document.getElementById('test'))
    

强烈注意

  • 1,组件中render方法中的this为组件实例对象

  • 2,组件自定义的方法中this为undefined,如何解决?

    • a. 强制绑定 this:通过函数对象的 bind()
    • b. 赋值语句 + 箭头函数 (推荐)
  • 3,状态数据,不能直接修改或更新,使用 setState 进行更改

    this.setState({ key1: value1, key2: value2, ... })
    

props


示例要求

需求:自定义用来显示一个人员信息的组件

  • 1,姓名必须指定,且为字符串类型;
  • 2,性别为字符串类型,如果性别没有指定,默认为男
  • 3,年龄为字符串类型,且为数字类型,默认值为 18

基本理解

  • 1,每个组件实例对象都会有 props (properties的简写) 属性
  • 2,组件标签的所有属性都保存在 props

基本作用

  • 1,通过标签属性从组件外向组件内传递变化的数据
  • 2,注意:组件内部不要修改 props 数据

基础实现

  • 1,内部读取某个属性值( 单个传递标签属性)

    • this.props.name
    // 1. 创建组件
    class Person extends React.Component {render () {return (<ul><li>姓名:{ this.props.name }</li><li>性别:{ this.props.sex }</li><li>年龄:{ this.props.age }</li></ul>)}
    }// 2. 渲染组件到页面
    ReactDOM.render(<Person name="tom" sex="女" age="18"/>, document.getElementById('test'))
    
  • 2,对 props 中的属性值进行类型限制和必要性限制

    • 第一种方式(React v15.5 开始已弃用):
    <script type="text/babel">// propTypes 属性规则// PropTypes 是 React v15.5 的内置对象Person.propTypes = {name: React.PropTypes.string.isRequired, age: React.PropTypes.number}
    </script>
    
    • 第二种方式(新):使用 prop-types 库进行限制(需要引入 prop-types 库)
    <!-- 引入 prop-types,用于对组件标签属性进行限制,返回 PropTypes 对象 -->
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">// 对标签属性进行类型、必要性的限制Person.propTypes = {name: PropTypes.string.isRequired, // 限制name必传,且为字符串sex: PropTypes.string, // 限制sex为字符串age: PropTypes.number, // 限制 number 为数值speak: PropTypes.func  // 限制 speak 为函数}
    </script>
    
    • props 的简写方式,将其 添加到类的自身
    class Person extends React.Component {// 给类自身添加属性,使用 static// 对标签属性进行类型、必要性的限制static propTypes = {name: PropTypes.string.isRequired, // 限制name必传,且为字符串sex: PropTypes.string, // 限制sex为字符串age: PropTypes.number, // 限制 number 为数值speak: PropTypes.func  // 限制 speak 为函数}// 指定默认标签属性值static defaultProps = {sex: '男', // sex 默认值为男age: 18 // age 默认值为18}
    }
    
  • 3,扩展属性: 将对象的所有属性通过 props 传递(批量传递标签属性 props )

    • <Person {...person} />
    // 1. 创建组件
    class Person extends React.Component {render() {const { name, sex, age } = this.propsreturn (<ul><li>姓名:{name}</li><li>性别:{sex}</li><li>年龄:{age}</li></ul>)}
    }// 2. 渲染组件到页面
    const p = { name: '老刘', sex: '女', age: 18 }
    // ReactDOM.render(<Person name={p.name} sex={p.sex} age={p.age} />, document.getElementById('test2'))// 利用 ... 展开运算符 进行批量属性传递
    ReactDOM.render(<Person {...p} />, document.getElementById('test2'))
    
  • 4,默认属性值:

    <script type="text/babel">// 指定默认标签属性值Person.defaultProps = {sex: '男', // sex 默认值为男age: 18 // age 默认值为18}
    </script>
    
  • 5,组件类的构造函数(能省则省)

    • 通过给 this.state 赋值对象来初始化内部 state
    • 为事件处理函数绑定实例
    constructor (props) {// 构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问propssuper(props)   console.log(props) // 打印所有属性   console.log(this.props) // 打印所有属性
    }
    
  • 6,函数式组件使用 props

    function Person(props) {console.log(props);const { name, sex, age} = propsreturn (<ul><li>姓名:{ name }</li><li>性别:{ sex }</li><li>年龄:{ age }</li></ul>)
    }
    Person.propTypes = {// ......
    }Person.defaultProps = {// ......
    }
    

refs与事件处理

示例要求

需求:自定义组件,功能说明如下:

  • 1,点击按钮,提示第一个输入框中的值

  • 2,当第2个输入框失去焦点时,提示这个输入框中的值

基本理解

  • 组件内的标签可以定义 ref 属性来标识自己

基本实现

  • 1,字符串形式的 ref (不建议使用)

    • <input ref="input1" />
    class Demo extends React.Component {// 展示左侧输入框的数据showData = () => {const { input1 } = this.refsalert(input1.value)}// 展示右侧输入框的数据showData2 = () => {const { input2 } = this.refsalert(input2.value)}render() {return (<div><input ref="input1" type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>点我提示左侧的数据</button><input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" /></div>)}
    }
    

    注意:
    ​ 使用过多,会产生效率问题。

  • 2,回调形式的 ref

    • 内联形式的回调:<input ref={ c => { this.input1 = c } }/>

      关于回调 refs 的说明

      如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

      class Demo extends React.Component {state = { isHot: true }showInfo = () => {const { input1 } = thisalert(input1.value);}changeWeather = () => {// 读取原来的状态const { isHot } = this.state// 更新状态this.setState({ isHot: !isHot })}// 将 ref 的回调函数定义成 class 的绑定函数的方式saveInput = (c) => { this.input2 = c }render () {const { isHot } = this.statereturn (<div><h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2><input ref={c => this.input1 = c} type="text" /><br />{/* 将 ref 的回调函数定义成 class 的绑定函数的方式 */}<input ref={this.saveInput} type="text" /><br /><button onClick={this.showInfo}>点击按钮输入的数据</button><button onClick={this.changeWeather}>点我切换天气</button></div>)}
      }
      
  • 3,createRef() 创建 ref 容器·(最推荐使用)

    • React.createRef() 调用后可以返回一个容器,该容器可以存储被 ref 所标识的节点
    • 该容器是 “专人专用” 的,即每一个容器内只能存放一个节点
    • 在这个容器中,存在一个 current 属性,指的是当前绑定的节点
    class Demo extends React.Component {// 将这个容器绑定到 组件实例中  myRef = React.createRef()myRef2 = React.createRef()// 展示左侧输入框的数据showData = () => {// this.myRef.current 指的是 input 节点alert(this.myRef.current.value);}// 展示右侧输入框的数据showData2 = () => {alert(this.myRef2.current.value)}render() {return (<div><input ref={this.myRef} type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>点我提示左侧的数据</button> &nbsp;<input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据" /></div>)}
    }
    

事件处理

  • 1,通过 onXxx 属性指定事件处理函数(注意 大小写)

    • a. React 使用的是自定义(合成)事件, 而不是使用的原生DOM事件 — 为了更好的兼容性
    • b. React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素) — 为了高效
  • 2,通过 event.target 得到发生事件的 DOM 元素对象 — 不要过度的使用 Refs

    class Demo extends React.Component {showData2 = (event) => {alert(event.target.value)}render() {return (<div><input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" /></div>)}
    }
    

    注意:

    ​ 必须保证将一个函数作为事件回调赋值给 onXxx 属性。

收集表单数据

示例要求

需求:定义一个包含表单的组件

  • 输入用户名密码后,点击登录提示输入信息

基本理解

包含表单的组件分类

  • 1,受控组件:页面中所有输入类(包括checkbox、radio等) DOM 的值,随着用户的输入,就可以将数据维护到状态中去,当使用时,直接在状态中取,这就属于 受控组件。(类似于 Vue 的双向数据绑定)

    class Login extends React.Component {// 初始化状态state = {username: '', // 用户名password: '' // 密码}handleSubmit = (event) => {// 阻止表单提交event.preventDefault();const { username, password } = this.statealert(`你输入的用户名是${username},你输入的密码是${password}`)}// 保存用户名到状态中saveUserName = (event) => {console.log(event.target.value);this.setState({ username: event.target.value })}// 保存密码到状态中savePassword = () => {this.setState({ password: event.target.value })}render () {return (<form onSubmit={this.handleSubmit}>用户名:<input onChange={this.saveUsername} type="text" name="username" />密&emsp;码:<input onChange={this.savePassword} type="password" name="password" /><button>登录</button></form>)}
    }
    
  • 2,非受控组件:页面中所有输入类(包括checkbox、radio等) DOM 的值,是现用现取的,就是 非受控组件

    class Login extends React.Component {handleSubmit = (event) => {// 阻止表单提交event.preventDefault();const { username, password } = thisalert(`你输入的用户名是${username.value},你输入的密码是${password.value}`)}render () {return (<form onSubmit={this.handleSubmit}>用户名:<input ref={c => this.username = c} type="text" name="username" />密&emsp;码:<input ref={c => this.password = c} type="password" name="password" /><button>登录</button></form>)}
    }
    

示例优化


高阶函数和函数柯里化

  • 高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数

    • 1,若 A 函数,接收的参数是一个函数,那么 A 就可以称之为 高阶函数
    • 2,若 A 函数,调用的返回值依然是一个函数,那么 A 就可以称之为 高阶函数
    • 常见的高阶函数有:PromisesetTimeoutarr.map() 等等
  • 函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数,最后统一处理的函数编码形式

  • 代码优化,如下所示:

    class Login extends React.Component {// 初始化状态state = {username: '', // 用户名password: '' // 密码}handleSubmit = (event) => {// 阻止表单提交event.preventDefault();const { username, password } = this.statealert(`你输入的用户名是${username},你输入的密码是${password}`)}// 保存表单数据到状态中saveFormData = (dataType) => {return (event) => {this.setState({ [dataType]: event.target.value })}}render () {return (<form onSubmit={this.handleSubmit}>{/* onChange 自动执行的是一个回调函数,因此 this.saveFormData('username') 必须要返回一个函数*/}用户名:<input onChange={this.saveFormData('username')} type="text" name="username" /><br /><br />密&emsp;码:<input onChange={this.saveFormData('password')} type="password" name="password" /><br /><br /><button>登录</button></form>)}
    }
    

不用柯里化的实现

  • 代码优化,如下所示:

    class Login extends React.Component {// 初始化状态state = {username: '', // 用户名password: '' // 密码}handleSubmit = (event) => {// 阻止表单提交event.preventDefault();const { username, password } = this.statealert(`你输入的用户名是${username},你输入的密码是${password}`)}// 保存表单数据到状态中saveFormData = (dataType, event) => {this.setState({ [dataType]: event.target.value })}render() {return (<form onSubmit={this.handleSubmit}>{/* onChange 自动执行的是一个回调函数,因此 this.saveFormData('username') 必须要返回一个函数*/}用户名:<input onChange={event => this.saveFormData('username', event)} type="text" name="username" /><br /><br />密&emsp;码:<input onChange={event => this.saveFormData('password', event)} type="password" name="password" /><br /><br /><button>登录</button></form>)}
    }
    

组件的生命周期

示例要求

需求:定义组件实现以下功能:

  • 1,让指定的文本做显示 / 隐藏的渐变动画

  • 2,从完全可见,到彻底消失,耗时 2S

  • 3,点击 “不活了” 按钮从界面中卸载组件

基本理解

  • 1,组件从创建到死亡它会经历一些特定的阶段。
  • 2,React 组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
  • 3,我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

基本实现

  • 引出生命周期,如下所示:

    // 渲染组件
    // 生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
    class Life extends React.Component {state = { opacity: 1 }death = () => {// 卸载组件ReactDOM.unmountComponentAtNode(document.getElementById('test'))}componentDidMount() {this.timer = setInterval(() => {// 获取原状态let { opacity } = this.state// 减小 0.1opacity -= 0.1if (opacity <= 0) opacity = 1// 设置新的透明度this.setState({ opacity })}, 200)}// 组件将要卸载componentWillUnmount () {// 清除定时器clearInterval(this.timer)}// 初始化渲染、状态更新之后render () {return (<div><h2 style={{ opacity: this.state.opacity }}>React 学不会,怎么办?</h2><button onClick={this.death}>不活了</button></div>)}
    }
    // 渲染组件
    ReactDOM.render(<Life />, document.getElementById('test'))
    

生命周期流程图(旧)

生命周期的三个阶段(旧)

  • 1,初始化阶段:ReactDOM.render() 触发 — 首次渲染

    • 1)constructor()

    • 2)componentWillMount():组件将要挂载的钩子

    • 3)render()

    • 4)componentDidMount():组件挂载完毕的钩子 ====> 常用

      • 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
  • 2,更新阶段: 由组件内部 this.setSate() 或父组件重新 render 触发

    • 1)shouldComponentUpdate():控制组件更新的“阀门”,默认返回 true,则状态改变时,更新组件;若设置返回 false,则状态改变时,不更新组件

    • 2)componentWillUpdate():组件将要更新的钩子

    • 3)render():=====> 必须

    • 4)componentDidUpdate():组件更新完毕的钩子

      注意:

      • 不更改任何状态中的数据,强制更新时,使用 this.forceUpdate(),它不受 shouldComponentUpdate() 的控制
      • 子组件 中有一个单独的钩子,即 componentWillReceiveProps,接收 props 参数
      • 它是在组件将要接收新的 props 的时候,调用的钩子,即初次渲染时,不调用,传入新值时,才会调用
  • 3,卸载组件:ReactDOM.unmountComponentAtNode() 触发

    • 1)componentWillUnmount():组件将要卸载的钩子 ====> 常用

      • 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

生命周期流程图(新)

生命周期的三个阶段(新)

  • 1,初始化阶段:ReactDOM.render() 触发 — 首次渲染

    • 1)constructor()
    • 2)getDerivedStateFromProps()
      • 静态方法,使用时需要 static 关键字进行修饰
      • 接收两个参数 propsstate
      • 必须要有返回值:要么是 null ,要么是 state object
      • state 的值在任何时候都取决于 props,那么可以使用 getDerivedStateFromProps()
      • 派生状态会导致代码冗余,一般不建议使用
    • 3)render()
    • 4)componentDidMount()
  • 2,更新阶段: 由组件内部 this.setSate() 或父组件重新 render 触发

    • 1)getDerivedStateFromProps()
    • 2)shouldComponentUpdate()
    • 3)render()
    • 4)getSnapshotBeforeUpdate:在更新之前获取快照
      • 必须要有返回值:要么是 null ,要么是 snapshot value

        • 任何值都可以作为 snapshot value (快照值)
      • 接收两个参数 prevPropsprevState,即 未改变之前的 propsstates
      • 返回值将作为参数传递给 componentDidUpdate()
    • 5)componentDidUpdate(prevProps, prevState, snapshotValue)
  • 3,卸载组件:ReactDOM.unmountComponentAtNode() 触发

    • 1)componentWillUnmount()

重要的勾子

  • 1,render():初始化渲染或更新渲染调用
  • 2,componentDidMount():开启监听, 发送ajax请求
  • 3,componentWillUnmount():做一些收尾工作, 如: 清理定时器

即将废弃的勾子

  • 1,componentWillMount
  • 2,componentWillReceiveProps
  • 3,componentWillUpdate

现在使用会出现警告,下一个大版本需要加上 UNSAFE_ 前缀才能使用,以后可能会被彻底废弃,不建议使用 。

虚拟DOM 与 DOM Diffing算法

示例要求

需求:验证虚拟 DOM Diffing 算法的存在

基本原理图

经典面试题:

1,react/vue中的key有什么作用?(key的内部原理是什么?)

  • 1)简单的说:key 是 虚拟DOM 对象的标识,在更新显示时key起着极其重要的作用。

  • 2)详细的说:当状态中的数据发生变化时,react 会根据【新数据】生成【新的虚拟DOM】,随后 React 进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

    • a. 旧虚拟DOM 中找到了与 新虚拟DOM 相同的 key :

      • (1) 若 虚拟DOM 中内容没变,直接使用之前的真实DOM
      • (2) 若 虚拟DOM 中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    • b. 旧虚拟DOM 中未找到与 新虚拟DOM 相同的 key
      • 根据数据创建新的真实DOM,随后渲染到页面

2,为什么遍历列表时,key 最好不要用 index ?

用 index 作为 key 可能会引发的问题:

  • 1)若对数据进行:逆序添加、逆序删除等破坏顺序操作:

    • 会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低。
  • 2)如果结构中还包含输入类的DOM:
    • 会产生错误DOM更新 ==> 界面有问题。
  • 3)注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
    • 仅用于渲染列表用于展示,使用index作为key是没有问题的。

3,开发中如何选择 key ?

  • 最好使用每条数据的唯一标识作为 key,比如 id、手机号、身份证号、学号等唯一值。

【React 基础】之 React 面向组件编程相关推荐

  1. React学习笔记2:React面向组件编程

    面向组件编程 概述 组件名必须首字母大写 虚拟DOM元素只能有一个根元素 虚拟DOM元素必须有结束标签 渲染类组件标签的基本流程 React内部会创建组件实例对象 调用render()得到虚拟DOM, ...

  2. 第二章:React 面向组件编程

    第二章:React 面向组件编程 2.1. 基本理解和使用 2.1.1. 效果 2.1.2. 自定义组件(Component) : 定义组件(2 种方式) /* 方式 1: 工厂函数组件( 简单组件) ...

  3. b站React禹哥版视频笔记-React面向组件编程(上)

    目录 前言 一.开发者工具的安装 二.函数式组件 三.复习类相关知识 四.类式组件 五.组件实例的三大核心属性1:state 1.对state的理解 2.初始化state 3.react中的事件绑定 ...

  4. .net 面向组件编程_试析C#编程语言的特点及功能

      摘要: 如今,从C#编程语言的发展前景分析,其可能在多个操作系统平台中编写各种实现,而从现实应用情况来看,大多数操作人员及编译器供应商已经将C#作为创建编译器版本的标准.本文从工作实践出发,主要对 ...

  5. Atitit 面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)的区别和联系...

    Atitit 面向对象编程(OOP).面向组件编程(COP).面向方面编程(AOP)和面向服务编程(SOP)的区别和联系 1. 面向组件编程(COP) 所以,组件比起对象来的进步就在于通用的规范的引入 ...

  6. 面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)

    1.什么是面向对象编程(Object-Oriented Programming)? 面向对象编程(Object-Oriented Programming)简称OOP技术,是开发计算机应用程序的一种新方 ...

  7. 第一章:Reac入门 与 第二章:React面向组件编程

    目录 一.jsx语法规则 二.React中定义组件 1.函数式组件: 2.类式组件:*有关类复习的知识点前往React知识铺垫查看https://blog.csdn.net/m0_61927991/a ...

  8. react基础入门,类组件和函数组件,state,props,refs

    React入门 目录 React入门 React入门 Vue跟React的异同点 相同点 不同点 Vue小建议 1. 不需要响应式的数据应该怎么处理? 2. Key 3. 数据结构 React 教程 ...

  9. React基础(貳)———组件

    一.组件 类组件 函数式组件 组件的嵌套 /*** rcc快捷键**/ import React, { Component } from "react";class Child e ...

最新文章

  1. 最新的ES 5.0路由算法底层实现
  2. c语言 空格_C语言100题集合-ex003
  3. scala 当前日期_如何在Scala中检查当前日期和时间?
  4. 的正确使用_如何正确使用安全带 安全带正确系法
  5. 超级楼梯(HDU-2040)
  6. java kafka 消费_java利用kafka生产消费消息
  7. Qt中文本编辑器实现语法高亮功能(Qscitinlla)
  8. 多线程(thread)+进程(Process)
  9. COJ-1271 Brackets Sequence
  10. [sitemap 索引情况提示] 根据 sitemap 的规则[0],当前页面 [pages/loading/loading] 将被索引
  11. 述职答辩提问环节一般可以问些什么_陕西省高级职称评审,90%的人都“死”在答辩上?...
  12. 《云计算核心技术剖析》读书笔记之一
  13. 软考高项--第一章项目整体管理
  14. pdf拆分成一页一页,pdf拆分方法
  15. 给文件及文件夹设置密码
  16. 啊哈算法, 水管工游戏
  17. Adidas Alpha bounce阿尔法运动如此强大,功能跑鞋真让人佩服
  18. verdi 文件格式转换及差异
  19. 马耳他新规要求所有房产租赁合同在区块链上登记
  20. 计算机相关专业提升学历的解决方案(本科及以下)

热门文章

  1. Windows下搭建IOS开发环境(一)
  2. 【BIOS来电重启】Restore AC Power Loss
  3. 【三维深度学习】点云上采样网络PU-Net 代码分析
  4. 第一条Pulsar消息发送
  5. sqlserver 日期函数
  6. 小动画制作 图片盒子配合定时器 winform 114869633
  7. python遍历获取一个类的所有子类
  8. 用层进表面预测来重建三维物体
  9. 从源码角度看Spark on yarn client cluster模式的本质区别
  10. Request 部分功能