react-5-从jsx到类组件的生命周期

react 笔记

jsx中绑定this

为什么this会是undefined ?

  1. 可以使用bind方式绑定this

<button onClick={this.sayHi.bind(this)}>{this.state.btnDes}</button>

  1. 可以使用箭头函数方式绑定this

<button onClick={() => this.sayHi()}>{this.state.btnDes2}</button>

jsx中的列表渲染

一般的,都是使用map进行列表渲染,同时返回一个jsx-dom

    <ul>
          {/* 在这里,一般用map来进行列表渲染 */}
          {
            this.state.movies.map((item, index) => <li onClick={() => this.getItme(item)} key={index}>{item}</li>)
          }
    </ul>

计数器案例

  1. setState的函数形式:

传递一个函数可以让你在函数内访问到当前的 state 的值。因为 setState 的调用是分批的,所以你可以链式地进行更新,并确保它们是一个建立在另一个之上的,这样才不会发生冲突

 this.setState((pre, next) => {
      console.log(pre, next);
      return {
        val: data
      }
    })

几点提示

pre : state更改前的上一次状态
next : state更改后的状态
函数式必须要return一个对象,分别对应state内的键值对

  1. 绑定属性

绑定属性类似原生小程序,如
<input onChange={(e) => { this.changeVal(e) }} value={this.state.val ? this.state.val : 0} />

  1. react并没有双向绑定,因而要使用e事件对象来找到值

  2. 关于num++ 与num+1
    要使用num+1

在使用setState的时候不能使用num++,否则会导致修改失败 ,并且在事件触发时state也只会保持原值

JSX语法

描述:jsx是js的拓展语法,想要使用jsx ,需要给script标签中添加 type="text/babel"属性

  1. jsx规范
  2. jsx顶部只允许有一个根元素,即便是空标签也可以
  3. jsx外层包裹一个小括号,一来方便阅读,二来可以换行书写
    3.jsx中的标签可以是单标签,也可以是双标签,但如果是单标签,需要/>结尾,如<img />, <div />
  4. jsx注释

通常使用{/* 这里是注释 */}来表示,在jsx上下文环境下,ctrl+/可以自动生成注释行

  1. jsx嵌入变量
    *. jsx中可以正常显示这些类型: string,number,array
    *. jsx中一般不能渲染以下数据类型(会显示dom,但不会显示dom的内容)

    1. null undefined

    如果必须要让null,undefined显示,可以使用String(null/undefined)的方式,也可以直接让其加''

    2.boolean

    如果必须要对bool显示,可以使用bool.tostring()方法变成字符串

    1. obj

    对象不能作为jsx的子类 =》 不允许直接在jsx中渲染obj本身,但可以渲染obj内部的key-value

jsx嵌入运算符

在render函数内,可以使用解构的方式将state内的数据拿出来

render() {
  const {cannotShow1,cannotShow2} = this.state
  return(
    <div>
      <p>render本质上是一个函数,只不过return了一个特殊的对象<p/>
    </div>
  )
}

jsx可以嵌入以下:

  1. 表达式

{fN + lN}

  1. 数学程式
  2. 三目运算
  3. 逻辑与
  4. 函数调用

如果是函数调用,则可以有vue-filter/computed(?有吗 有待考证)

jsx绑定属性

  1. 一般的可以直接使用
<p title={'这是' + '绑定属性'}> </p>
  1. 但有的会与js本身的关键字/保留字冲突,此时要自主更换,遵循jsx规约
    如:
    class => className
    for => htmlFor
jsx绑定class(重点)

jsx下的class要用className替代,想要绑定className样式,需要使用大括号语法

元素普通的class名,用引号包裹即可

<span className='hehehe'>这里是普通class</span>

被绑定了class的元素,外部需要用大括号,这个大括号是jsx语法,普通class与三木运算class需要保留间隔

<span className={'hhh jjj ' + (isTrue ? 'istrue' : '')}>绑定class时,外部包裹大括号,因为class也是属性</span>

jsx绑定style(重点)

style属性必须是一个对象格式,当key是两个字符时,遵循小驼峰格式,value不加引号时会被认为是一个变量
<span style={{ border: '1px solid red', background: 'red' ,}}>绑定style</span>

jsx绑定事件

jsx绑定事件,事件名 依旧要使用小驼峰标识

jsx如果不绑定this的话,将不能找到类组件本身的constructor里的state(提示state of undefined),

想要找到正确的this值,需要绑定this,有以下三种方法

  1. jsx中显式绑定this
    <div onClick={this.sayHi.bind(this)}></div>

缺陷,易导致冗余代码产生

  1. 构造器内,super下绑定this
constructor(props){
  super(props)
  {/*本质上是给原来的函数事先绑定后this,然后又重新赋值给这个函数 
      在之前比较常用
  */}
  this.sayHi = this.sayHi.bind(this)
}   
  1. jsx中给dom绑定事件时使用箭头函数
<div onClick={() => this.sayHi()}>11111</div>

请注意:箭头函数下,内部函数必须要加小括号表示执行!

  1. 声明函数时,不再声明普通函数,而是声明箭头函数

原因:箭头函数在声明时无法绑定this,因而自动一层层向上寻找值(隐式),这种本质上是使用es6中给类添加属性的方法 class fileds

 //外部触发的函数在声明时使用箭头函数

 sayHi = () => {
   console.log(this.state.isTrue)
 }

 <div onClick={this.sayHi}>11111</div>
jsx什么时候写大括号?

大括号里写什么 取决于你希望在这个大括号里返回什么

条件判断

react逻辑判断遵循js原生逻辑
*一: 如果逻辑很多,可以使用if判断,
*二: 如果逻辑很少,可以使用三目运算符判断,
*三: 三木运算符与&&逻辑与, v-if / v-show
*四: 本质上是&&逻辑与完成了与v-if相同的效果,即在dom中先删除再生成
*五: 想要完成v-show,可以操作style的display属性

map与filter的组合渲染
  1. 过滤再截取

很多时候只希望渲染符合条件的所有list,因而可以先使用filter再使用map的方式

{/*
先使用filter过滤不符合条件的,此时该数组内只剩下符合条件的,然后再使用map渲染列表
*/}
<ul>
          {
            numArr.filter(item => item > 90)
              .map(v => <li>{v}</li>)
          }

</ul>

2.过滤截取再渲染

<ul>
          {
            numArr.filter(item => (item > 30) && (item < 100))
              .slice(0, 4)
              .map(v => <li>{v}</li>)
          }

</ul>

总结:jsx允许在map渲染前对原数组进行任何js允许的操作

jsx源码

  1. jsx的本质
    在普通script标签中无法写jsx的原因是,jsx最终要经过ReactDOM.createElement()将其编译成语法糖
    ReactDOM.createElement(type,config,children)

传入三个参数:
*. type: 当前ReactElement传入的类型
如果是元素标签,那么就用字符串表示'div'
如果是组件标签,那么就直接使用组件名称
*. 当前ReactEle的属性以及事件,以键值对对象的方式进行存储
*. children
存放在ReactEle中的内容,以children数组的方式进行存储
如果有多个子元素,需要用babel进行转换

问题:为什么参数第三个属性是一个参数并且不是一个可变参数,但是编译后却并不报错?

使用auguments来对后面的参数进行一一匹配:
const sonArr = auguments.length - 2 //减去2的原因是减去精准匹配参数1,精准匹配参数2

通过createElement()最终生成了一颗js dom树,这棵树(js对象)就是虚拟dom树 React.render负责将这颗dom树映射到指定的真实dom节点上,从而将虚拟dom树变成了真实dom树结构(浏览器中),RN中其实都相同,只是没有渲染真实dom,而是渲染成了安卓、ios的原生控件,taro?
流程:jsx => createElement(jsx) => render(createElement(jsx),DOM) = > 真实dom
render.dom将虚拟dom与真实dom一一映射,这个叫做映射

为什么要使用虚拟dom
  1. 很难追踪状态发生的改变
  2. 操作真实dom性能较低

    dom操作会引起浏览器的回流和重绘
    设计原则: 元数据的不可变性,【1.只允许使用setstatus修改数据,2.尽量生成新数据而不修改元数据(如果是引用类型,可以进行浅拷贝,然后再赋值进去)】

以render函数为界:
功能函数一般放在render函数后面
组件函数放在render前面

react-cli 中package.json的版本区别

 "dayjs": "^1.10.5" 

1.10.5:表示目标库始终使用这个版本
^1.10.5:表示小版本更新【"5"可变】

弊端:小版本更新也可能造成版本之间误差,yarn.lock文件表示安装的具体详细版本

yarn eject的作用

暴露react-cli的webpack配置,但这是不可逆的
执行后会暴露config目录和script目录
执行后package.json会暴露react内部的一些依赖库
执行后package.json的script每一项的value会发生变化:

// 之前是这样
  "start": "react-scripts start --open",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"

// 现在是这样  script目录:执行eject后暴露出的目录
  "start": "node script/start.js --open",
  "build": "node script/build.js",
  "test": "node script/test.js",

修改src源代码会直接热更新,修改config目录、script目录时需要重新运行

vscode自动补全jsx插件

htmltagwrap

react组件的类型

  1. 根据组件的定义方式 分为 函数式组件与类组件
  2. 根据组件内部是否需要维护,分为无状态组件与有状态组件
  3. 根据组件的不同职责,可以分为展示型组件和容器型组件

以上定义方式有很多重叠,但主要都关注数据逻辑与ui展示的分离

  1. 函数组件,无状态组件,展示型组件主要关注UI的展示
  2. 类组件,有状态组件,容器型组件主要关注数据逻辑

jsx中标签规范

普通标签不允许大写,jsx会认为是未定义的组件

组件规约

  1. 凡是组件必须大写字符开头
  2. 类组件需要继承React.Component(16.3后可直接继承Component)
类组件
  1. constructor是可选的,通常在内部初始化数据(this指向,定义组件变量,接收父组件数据)
  2. constructor中的this.state用于初始化组件内部需要的数据(es7中,可以在constructor外部使用state={xx:xxx}达到相同结果)
  3. render是类组件中唯一需要实现的方法

函数式组件

  1. 没有内部状态
  2. 没有this对象

render函数的返回值

不管是函数式组件还是render函数

  1. react元素

  2. 数组或者fragments:=》 使得render方法可以返回多个元素

不允许返回对象!

插件快捷键~ ES7 React/Redux/React-Native/JS snippets

  1. rcc => 生成类组件
  2. rfc => 生成函数式组件
  3. imd => 从库中全部导入
  4. imn => 导入库(如css)
  5. imd => 从库中导入某个变量函数
  6. cp => 从props中解构
  7. cs => 从status中解构
  8. clo => console.log(obj,obj) //obj此时被选中
  9. imr→ import React from 'react'
  10. imrc => import React,{Component} from 'react'

多退少补

生命周期

人或物从诞生到消亡的整个过程

react的生命周期分为三种:

  1. mount: 组件初次被渲染的阶段(mounting)

constructor :

comoponentDidmount:

  1. updata: 组件数据更新,重新更新渲染的阶段updating

render: 接收props或者setstatus或者强制刷新dom时都会重新调用render函数

componentDidUpdate

  1. unmount:组件从dom树中被移除的阶段unmounting

componentWillUnmount

执行顺序 =》 constructor => render => react内部开始更新或挂载组件 =》 componentDidmount/componentDidUpdate

类组件版父子组件

import { Component } from 'react'
class Son extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }
  render() {
    return (
      <div>
        <p>我是子组件</p>
      </div>
    )
  }
}
class App extends Component {
  constructor(prop) {
    super(prop)
    this.state = {
    }
  }
  render() {
    return (
      <div>
        <p>这是父组件</p>
        <Son />
      </ div>
    )
  }
}
export default App

在一个大组件文件里,一个小组件可以定义在这个组件里,然后直接导入大组件内部即可,请注意: 必须保证是纯函数!

纯函数:在输入时就能保证输出的数据类型和值,且无副作用

待续。

作者:致爱丽丝
本文版权归作者和博客园共有,欢迎转载,但必须在文章页面给出原文链接并标名原文作者,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/hjk1124/p/14990824.html