react基本认知,react基本使用,jsx,组件相关知识,react组件

289 阅读12分钟

react基本认知

是什么?

用于构建用户界面的js库

在学习react之前我们一般是

1,发送请求获取数据

2,处理数据(过滤,整理格式等)

3,操作dom呈现页面

react只关注界面(视图)帮助开发者不需要自己操作dom他是一个将数据渲染为html视图的开源js库

由facebook开发

为什么要学

原生js操作dom繁琐,效率低(dom-api操作ui),使用js直接操作dom,浏览器会进行大量重绘重排,原生js没有组件化编码方案,代码复用率低。

简单补充组件化:将一个整体拆分为一个个单独功能的代码片段,每一个组件代表一个功能模块,方便复用

1648360298050.png

react的特点

1.采用组件化模式,声明式编码,提高开发效率及组件复用。之前我们所使用的式命令式编程。例如我要把一个盒子背景颜色改变,首先得获取这个盒子,然后自己去操作dom修改样式缺少一步都无法达成。而声明式就像你告诉他改什么颜色,react就会通过一些特殊的语法帮你改变。

2.在react Native中可以使用react语法进行移动端开发。让我们前端可以使用它开发安卓和苹果应用。

3.使用虚拟dom+diff算法,尽量减少与真实dom交互。不用我们亲自操作dom。最小化页面重绘重排

虚拟dom:不是真实dom,是react用的,存在电脑内存。

1648361171742.png

1648361387447.png

react拿到数据后会存储在虚拟dom中然后在放入页面中,当数据发生更新的时候,react会采用diff算法,将虚拟dom与真实dom做比较。将已有的数据不动,只会将新增的数据渲染到页面中,对比于原生js全部替换,更高效

react基本使用

1648444363038.png

**1:**首先引入相关包,react核心包,和react帮助我们操作dom的包,babel作用:帮助浏览器转换某些高级语法比如es6语法转es5,此处由于react使用的是jsx而并非js,所以需要借助babel进行转换

**2:**准备一个容器,用于放置虚拟dom

**3:**创建虚拟dom

**4:**使用reactdom包提供的方法渲染dom到页面

为什么react使用jsx而非js

1648445552204.png

js创建虚拟dom繁琐;使用react.createElement方法

jsx可以很轻松的将繁琐的步骤转化为js方式,作为使用者我们会很轻松简单

关于jsx

1648446082653.png

1648446035320.png

jsx语法规则

  1. 虚拟dom的标签不要加引号

  2. 虚拟dom只能有一个根目录

  3. 标签必须闭合

  4. 如果标签中混入js表达式必须使用{}包裹

  5. 样式的类名不能用class指定,必须使用className

  6. 内联样式必须按照style={{key:value}}这种形式去写,第一个{}表示里面要写js表达式,第一个表示里面写的是对象的形式

  7. jsx里面写的不是html,是jsx的html的语法。他会帮里面的标签转换为html。如果标签是小写字母开头他会去寻找同名的html元素渲染,若没有对应的,则报错。若是大写开头。会去寻找相应的组件。若组件未定义。则报错

模块与组件,模块化与组件化的理解

1648452332892.png

react组件

函数式组件

适用于定义简单组件

<div id="test"></div>
     <!-- react核心库 -->
     <script src="../js/react.development.js"></script>
     <!-- react扩展库 用于支持react操作dom-->
     <script src="../js/react-dom.development.js"></script>
     <!-- bable e6转es5 jsx转js -->
     <script src="../js/babel.min.js"></script>
     <script type='text/babel'>
        //  创建函数式组件
        function Mycomponent() {
            console.log(this);  //此处的this是undefined,因为bebel编译后开启了严格模式
             return <h2>我的函数式组件</h2>
         }
        //  渲染组件到页面
         ReactDOM.render(<Mycomponent/>,document.getElementById('test'))
        //  执行了reactdom发生了什么?
        // 1.react解析标签,找到了mycomponent组件
        // 2.发现组件使用函数定义的,随后调用该函数,将返回的虚拟dom转为真实dom呈现在页面
     </script>

类式组件

复习类相关知识

1648520942684.png

类式组件基本使用

首先创建一个类,这个类必须继承于react里面的一个类,类里面暂时可以不写构造器,后面补充,必须写render函数,函数必须有返回值!

适用于复杂组件

div id="test"></div>
     <!-- react核心库 -->
     <script src="../js/react.development.js"></script>
     <!-- react扩展库 用于支持react操作dom-->
     <script src="../js/react-dom.development.js"></script>
     <!-- bable e6转es5 jsx转js -->
     <script src="../js/babel.min.js"></script>
     <script type='text/babel'>
        //  创建类式组件
       class Mycomponent extends React.Component{
        //    render放在类的原型对象上,供实例使用,render中的this指向实例对象
           render(){
               return <h2>我是一个类似组件,适用于复杂组件</h2>
           }
       }
       console.log(React.Component);
       var oo=new Mycomponent()
       console.log(oo);
        //  渲染组件到页面
         ReactDOM.render(<Mycomponent/>,document.getElementById('test'))
        //  执行了reactdom发生了什么?
        // 1.react解析标签,找到了mycomponent组件
        // 2.发现组件使用类定义的,随后new出来该类的实例,
        // 并通过该实例调用render方法将render返回的虚拟dom转为真实dom呈现在页面
     </script>

区分复杂组件和简单组件

如果你的组件是有状态的,称为复杂,反之即为简单

状态:state

组件实例的三大核心

state

state中存储着数据,数据的改变就会驱动着页面的展示

state是组件中最为重要的属性,值是对象(包含多个key value)

组件被称为状态机,通过更新组件的state来更新相应的页面展示(重新渲染组件)

state使用说明。state一般存储着数据,一般我们采用对象的形式存储

如何读取state

state是组件实例的核心,存储在组件实例身上,this.state.xxx即可读取到他里面的属性

如何修改state

我们在修改state的时候不能直接修改,必须借助一个方法:setstate。这样才能生效

1648535854968.png

1648536034793.png

state的简写形式

在上面我们简单使用state修改数据的案例中,我们由于需要对组件实例的state进行初始化赋值,(初始值为null),不得不写构造器函数,虽然这种方法没有错误,但是我们可以用跟简便的方法实现。在类里面我们可以直接写赋值语句,例如a=1这时候就相当于给类的实例对象添加了一个属性为a,值为1.同样的我们可以写this.state={key:value}。然后我们再给类添加自定义方法的时候,由于经常都是作为回调去使用的,所以这个时候的this指向的不是组件实例。因为类里面的方法默认开启了严格模式,这时候指向的是undefined。在上面我们采用了bind方法在构造器里面改变了this指向。我们现在可以采用一种更简单的方式,还是采用赋值的思想,将自定义函数名等于一个函数。此函数为箭头函数,这时候相当于给但当前的类添加了一个属性,属性值是一个函数,并且我们使用箭头函数,箭头函数没有自己的this,指向的是外层的this。所以巧妙的实现了功能。

总结:类里面可以写赋值语句。并且在使用自定义方法时候,都要使用赋值语句加箭头函数 我们在使用state的时候,通常需要在里面存放一些数据,以便数据改变驱动页面更新,这时候我们必须使用构造器对state进行初始化,然而有更简单的方式可以不用使用构造器

在类里面我们可以直接使用赋值语句.例如a=1这句话的意思是在类的实例对象身上放了一个属性名a属性值为1的属性他等同于在构造器里面写this.a=1同样我们可以使用state={}的形式直接对state进行初始化.

在给类添加自定义事件的时候我们也可以用这种方式.先看一下不简写:此函数是放在类的原型对象上,如果想要访问this,必须要由实例调用,我们知道一般我们在类里面所写的自定义函数都是作为一种回调的方式来使用,比如点击了之后把这个函数调用,这时候我们无法访问到state里面的数据,因为jsx在所有函数的内部都默认开启了严格模式,在严格模式下禁止函数内的this指向window.如果想要访问到我们采取在构造器里面写上this.fn=this.fn.bind(this),bind再不调用的情况下生成一个新的函数,构造器里面的this是组件实例对象.这就等同于给组件实例对象添加一个属性fn是一个函数,而这个函数里面的this指向组件实例.这种方法我们可以简化

采用箭头函数赋值的形式 ,上面我们讲到在类里面可以赋值我么可以写成fn=()=>{}由于箭头函数的this是外部的this所以这时候我们就轻松的得到一个挂在组件实例的函数

补充react里面的事件都要加大写如onClick

props

官方定义: 当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”

props的作用

作用:用于接收组件外部的数据 传递数据: 通过给组件标签添加属性 接收数据:函数组件通过 参数 props接收数据,类组件通过 this.props接收数据

props的特点

  • 可以给组件传递任意类型的数据
  • props是只读属性,不能对值进行修改
  • 使用类组件时,如果写了构造函数,应该将props传递给super(),否则无法在构造函数中获取到props,其他的地方是可以拿到的

对prop传递的数据类型进行限制

需要依赖props这个包

使用方法

给类添加一个propstype属性 是一个对象

 Person.propTypes={
          name: PropTypes.string,
          age:PropTypes.number.isRequired限制必须传
        }

也可以设置默认值

 Person.defaultProps={
            sex:'不难不女'
        }

props的简写形式

我们可以使用类.xxx来给类添加属性.我们也可以在构造器里面使用static关键字给类添加属性

1649411793977.png

1649412808746.png

refs和事件处理

refs用来给元素打标示

字符串方法

ref='xxx'获取:this.refs.xxx这种方法基本弃用

内联函数方法:

ref={(a)=>{this.xxx=a}}其中参数a代表当前节点this.xxx=a代表在实例身上放置xxx属性值是当前节点

获取直接this.xxx

React.creatRef方法

该方法返回一个容器用于接收被ref所标识的节点

例如myref=React.creatRef()

将挂在实例的属性myref使用this.myref放入ref中

事件处理

1649419888892.png

react使用事件委托,给最外层元素绑定事件,通过事件冒泡触发事件,在触发事件的元素和我们要操作的元素是同一个可以不使用ref,使用 event.target

受控组件非受控组件

高阶函数以及函数柯里化

生命周期

什么是生命周期

理解:

1组件在创建到销毁他会经历一些特定的阶段-

2react组件中包含一系列钩子函数(生命周期回调函数),会在特定的事件调用

3我们在定义组件的时候,会在特定的生命周期回调函数中,做特定的工作

旧生命周期

1649565681898.png

销毁组件语法:unMountComponentAtNode(document.queryselector())

shouComponentUpdate钩子:控制组件更新的阀门

如果不写默认返回真,如果写了必须写返回值 返回真阀门开启,返回假阀门关闭

forceUpdate:在不更新状态的情况下 强制更新组件.不受阀门影响

componentwillReceiveProps钩子:父组件render后子组件即将收到新的props

第一次render这个函数不会被调用,必须等下次父组件更新触发render.这个函数也能收到参数props

1649571525892.png

常用:componentDidMount一般在这个钩子中做一些初始化的事,例如开启定时器,发送网络请求,订阅消息

常用:componentWillUnmount()一般做一些收尾的事例如取消订阅,关闭定时器

新生命周期

1649578911763.png

新的生命周期废弃了三个旧的钩子新增了两个钩子

废弃的钩子有:

  1. componentWillMount

  2. componentWillUpdate

  3. componentWillReceiveProps

新增的钩子有:

  1. getDerivedStateProps意为获得衍生的派生的,再使用他时必须加上static静态成员关键字,这意味着他是给类使用的

  2. getSnapshotBeforeUpdate在更新完成之前可以return一下数据过去,比如滚动的高度之类,在componentDIdUpdate里面可以收到三个参数分别是更新之前的state,props,和此钩子函数传过来的数据.

  3. 使用场景不多

即将废弃的钩子

  1. componentWillMount

  2. componentWillUpdate

  3. componentWillReceiveProps

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

用createReactApp快速创建一个案列解释一下新的两个钩子

bdb8442912f947938ac8df4961ee5d09_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp

getDerivedStateFromProps

app.js组件上新增一个按钮和一个状态值,点击按钮使得count + 1。 接下来引入getDerivedStateFromProps钩子

getDerivedStateFromProps() {
    console.log('00000000000000')
  }
复制代码

当这样写这个钩子后,和我们写的普通函数没什么区别,会报错

(react基础认知和使用.assets/bdb8442912f947938ac8df4961ee5d09_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) 根据错误信息,可见这个钩子前面得加static关键字,这说明,不是给实例使用的,而是类自身调用的。并且这个钩子内部必须有返回值,返回值是一个state状体对象(返回的对象和组件的state的key:value;保持一致)或者返回null。 当内部返回一个状态对象时:

state = {
    count: 0
  }
  static getDerivedStateFromProps() {
    return {
      count: 100
    }
  }
复制代码

(react基础认知和使用.assets/1e353b9f8bc14b2aac4a6d49da3019ac_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) 并且点击按钮,count不再 + 1,返回的状态对象影响到了页面的更新(看新版本钩子图可知,它在render前面),并且以返回的状态对象为主。 getDerivedStateFromProps钩子有2个参数,可以拿到组件传递的props和当前的组件状态。

state = {
    count: 0
  }
  static getDerivedStateFromProps(props,state) {
    return props;
  }
  
  // index.js组件传递props
  ReactDOM.render(
  <React.StrictMode>
    <App count='200' />
  </React.StrictMode>,
  document.getElementById('root')
);
复制代码

此时页面count变为了200 !(react基础认知和使用.assets/2db66ad5029c4d6290c1260bd04c3f9d_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) 总结:官方说道:此方法适用于罕见的用例,但是也得了解了解,在适当环境下也可以采用。

getSnapshotBeforeUpdate

在引入getSnapshotBeforeUpdate之后,再引入componentDidUpdate钩子。否则报错

(react基础认知和使用.assets/975bd60022de4cfcbc7a32a6649f6b3a_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) (react基础认知和使用.assets/c1ae23eaabfd425aadaf3e14c7157a76_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) getSnapshotBeforeUpdate有两个参数,分别是上个props上个state,暂时先返回null。

state = {
    count: 0
  }
  // static getDerivedStateFromProps(props) {
  //   return props;
  // }
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log(prevProps, 'prevProps')
    console.log(prevState, 'prevState')
    return null;
  }
  componentDidUpdate(prevProps,prevState) {
    console.log(prevProps,prevState)
  }
复制代码

点击按钮触发页面更新

(react基础认知和使用.assets/35a7e2a968784a0f909cc5ce70b1b671_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) 在getSnapshotBeforeUpdate钩子中返回一个存在的值,就可以在componentDidUpdate钩子的第三个参数接到。

getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log(prevProps, 'prevProps')
    console.log(prevState, 'prevState')
    return 'Faker';
  }
componentDidUpdate(prevProps,prevState,c) {
    console.log(prevProps,prevState,c)
}
复制代码

(react基础认知和使用.assets/d938ffdb45ee49a5b8cbe25aecaa3342_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp) 总结:因为getSnapshotBeforeUpdate在render和componentDidUpdate之间,既在页面完成渲染之前触发,比如获取滚动位置。这个钩子还是比较常用的。

diff算法

1649582294273.png

1649582871118.png

1649582107024.png