React基础

news/2024/11/20 9:34:07/

文章目录

    • 1.简介
      • 1.1 react与vue
        • 1.1.1 相同点
        • 1.1.2 不同点
        • 1.1.3 函数式组件的特点(什么是函数式组件)
          • a.幂等
          • b.无副作用用:
        • 1.1.4 虚拟dom的作用
        • 1.1.5 vue当中template与render的关系:
      • 1.2 MVC、MVVM、MVP模式
        • 1.2.1 MVC
        • 1.2.2 MVVM
        • 1.2.3 MVP
    • 2.JSX
      • 2.1 预防XSS攻击
      • 2.2 JSX表示对象
    • 3.State和Props
      • 3.1 Props
      • 3.2 State
        • 3.2.1 只能通过setState赋值
        • 3.2.2 更新可能是异步
        • 3.2.3 批量更新的优化
    • 4. 生命周期
      • 4.1 旧版生命周期(react<16.0.0)
      • 4.2 新版生命周期
        • 4.3.1 挂载阶段
            • constructor
            • getDerviedStateFromProps
            • render
            • componentDidMount()
        • 4.3.2 组件更新阶段
            • shouldComponentUpdate
            • getSnapshotBeforeUpdate
            • componentDidUpdate
        • 4.3.3 组件卸载阶段
            • componentWillUnmount

1.简介

React 是一个用于构建用户界面的 JAVASCRIPT 库,主要用于构建 UI,很多人认为 React 是 MVC 中的 V。
起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。

  1. 声明式设计 −React采用声明范式,可以轻松描述应用。
  2. 高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
  3. 灵活 −React可以与已知的库或框架很好地配合。
  4. JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
  5. 组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
  6. 单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。

1.1 react与vue

1.1.1 相同点

  • 都是数据驱动视图。
  • 采用虚拟dom+diff算法,但是react16以后推出了Fiber双缓存。
  • 鼓励组件化

了解React

1.1.2 不同点

写法上: react是js的一个库,使用jsx语法,将js与html结合,更让人觉得自己在写代码;vue更像是一个前端框架,具有侵入性,有自己的语法。
核心思想上: vue为双向绑定。react推崇函数式编程,单行数据流的特性,需要双向要使用onChange和setState去实现。
diff算法: 都是按照tree这样的维度,vue从两侧像中间递归,react从左到右。
响应式原理不同:

  • react主要是通过setState()方法来更新状态,状态更新之后,组件也会重新渲染。
  • vue2.0:当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim(降级) 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。(对象属性拦截)
  • vue3.0:Vue3的响应式原理是通过Proxy来完成的。Proxy直接监听对象,而非属性,所以将多个属性转换成getter/setter的时候,不需要使用循环。(对象整体代理)

1.1.3 函数式组件的特点(什么是函数式组件)

a.幂等

只要输入值不变,输出值也不变。输出结果完全由输入决定的,输出的结果也不会因为多次调用而发生改变。
例:splice方法,两次传入值一样,返回值不一样,不满足幂等(不满足原因:改变原数组)
在这里插入图片描述
slice方法,传入值一样,返回值不变,满足幂等(没有改变原数组)
在这里插入图片描述

b.无副作用用:

不会对外界造成影响(如:发起ajax请求,设置localStorage等)。

1.1.4 虚拟dom的作用

保证性能下限。不需要手动做太多的优化,就能够开发出有一定性能的应用

1.1.5 vue当中template与render的关系:

vue默认是template渲染,可以没有render方法。vue在编译时,先去判断组件里有没有render方法,如果没有,就会把当前的template转换成render方法,最后产出的就是template里面的元素。以render为最高优先级,如果没有render就会把template转换为render。

1.2 MVC、MVVM、MVP模式

1.2.1 MVC

在这里插入图片描述

MVC是指Model、VIew和Controller:
View层: 负责显示逻辑。
Model层: 负责存储页面的业务数据,以及对应数据的操作。
Controller层: 负责应用与用户的相应操作。

当用户与页面交互, View 需要更新时,首先去找 Controller,然后 Controller 通过调用Model层,来完成对Model层的修改,然后Model层再去通知VIew层更新。

其中 View 和 Model 应用了观察者模式,当 Model 层发生改变的时候它会通知有关 View 层更新页面。

1.2.2 MVVM

在这里插入图片描述

MVVM 分为 Model、View、ViewModel:
Model: 代表数据模型,数据和业务逻辑都在Model层中定义
View: 代表UI视图,负责数据的展示
ViewModel: 负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作;
Model和View并无直接联系,而是通过ViewModel来进行联系的,Model层和VIeModel层有着双向数据绑定的联系,因此Model中的数据改变时会触发View的刷新,用户在view层操作而改变的数据也会在Model层同步。

这种模式实现了Model层和View层的数据自动同步,开发者不需要自己操作DOM。

1.2.3 MVP

在这里插入图片描述
view需要更新数据时,首先去找Presenter,然后Presenter去找Model请求数据,Model获取到数据之后通知Presenter,Presenter再通知view更新。
View和Model不会直接交互,所有的交互都是由Presenter进行,Presenter充当了桥梁的作用。而Presenter必须同时拥有View和Model的对象的引用。

MVC中使用了观察者模式,当Model层发生改变时,View层更新。这样VIew层和Model层耦合在一起,当项目中逻辑变得负责是,可能造成代码混乱。

MVP中通过Presenter来实现对View层和Model层的解耦。MVC中的Controller只知道Model的接口,因此它没办法控制view层的更新。

MVP中,view层的接口暴露给了Presenter,因此可以再Present中将Model和View的变化绑定在一起,以此来实现VIew和Model的同步更新。这样就实现了View好Model的解耦。

2.JSX

JSX称为JS的语法拓展,在view层将内容书写进去,可以包含一些逻辑,通过逻辑与web组合实现一个基本的react描述。其实就是将js和html结合起来书写

2.1 预防XSS攻击

点此了解XSS攻击

2.2 JSX表示对象

const element = (<h1 className="greeting">Hello, world!</h1>
);

Babel会把JSX转移成一个名为React.createElement()函数调用

const element = React.createElement('h1',{className: 'greeting'},'Hello, world!'
);

通过React.render,将JSX渲染为DOM

// 使⽤ReactDOM.render
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

3.State和Props

3.1 Props

组件无论是使用函数声明还是通过class声明,都绝不能修改自身的props
props 作为组件对外通信的一个接口,为了保证组件像纯函数一样没有响应的副作用,所有的组件都必须像纯函数一样保护它们的props不被修改

3.2 State

如果视图内的数据需要修改, 并且同时页面响应变化,我们需要将数据放在state中, 使用setState来修改数据。它是组件本身的一个作用域。

3.2.1 只能通过setState赋值

不生效(视图无法更新):

//   请不要直接修改状态值//   this.state.counter += 1;

3.2.2 更新可能是异步

  1. setState 只在合成事件和⽣命周期中是“异步”的,在原⽣事件和 setTimeout 中都是同步的:
    setState的“异步”并不是说内部由异步代码实现,其实本身执⾏的过程和代码都是同步的, 只是合成事件和钩⼦函数的调⽤顺序在更新之前,导致在合成事件和钩⼦函数中没法⽴⻢拿到更新后的值,形式了所谓的“异步”, 当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果
  2. setState第一个参数可以是一个函数,这个函数的第一个参数可以拿到上一个state的值。setState的第二个参数可以是一个函数,这个函数的参数可以拿到setState改变状态之后的值

例1:


// 不生效,因为异步,第二次调用无法拿到第一次更新的值
this.setState({ counter: this.state.counter + 1 })
this.setState({ counter: this.state.counter + 1 })
this.setState({ counter: this.state.counter + 1 })// 生效,第一个参数可以拿到上一个state的值this.setState(prevState => ({counter: prevState.counter + 1}));this.setState(prevState => ({counter: prevState.counter + 1}));this.setState(prevState => ({counter: prevState.counter + 1}));

例2:

 this.setState({n: this.state.n + 1}, () => {//状态完成改变之后触发,该回调运行在render之后//可以拿到第一个参数改变之后的值console.log(this.state.n);});

3.2.3 批量更新的优化

setState 的批量更新优化也是建⽴在“异步”(合成事件、钩⼦函数)之上的,在原⽣事件和setTimeout 中不会批量更新,在“异步”中如果对同⼀个值进⾏多setState , setState 的批量更新策略会对其进⾏覆盖,取最后⼀次的执⾏(如上例1 )。
如果是同时 setState 多个不同的值,在更新时会对其进⾏合并批量更新。

componentDidMount() {fetchPosts().then(response => {this.setState({posts: response.posts});});fetchComments().then(response => {this.setState({comments: response.comments});});}

这里的合并是浅合并,所以 this.setState({comments}) 完整保留了 this.state.posts, 但是完全替换了 this.state.comments。

4. 生命周期

4.1 旧版生命周期(react<16.0.0)

在这里插入图片描述

import React, { Component } from "react";
export default class Lifecycle extends Component {constructor(props) {super(props);// 常用于初始化状态console.log("1.组件构造函数执行");}componentWillMount() {// 此时可以访问状态和属性,可进行api调用等console.log("2.组件将要挂载");}componentDidMount() {// 组件已挂载,可进行状态更新操作console.log("3.组件已挂载");}componentWillReceiveProps() {// 父组件传递的属性有变化,做相应响应console.log("4.将要接收属性传递");}shouldComponentUpdate() {// 组件是否需要更新,需要返回布尔值结果,优化点console.log("5.组件是否需要更新?");return true;}componentWillUpdate() {// 组件将要更新,可做更新统计console.log("6.组件将要更新");}componentDidUpdate() {// 组件更新console.log("7.组件已更新");}componentWillUnmount() {// 组件将要卸载, 可做清理工作console.log("8.组件将要卸载");}render() {console.log("组件渲染");return <div>生命周期探究</div>;}
}

4.2 新版生命周期

在这里插入图片描述

  • 挂载阶段(Mount):组件第一次在DOM树中被渲染的过程
  • 更新阶段(Update):组件状态发生变化,重新更新渲染的过程
  • 卸载过程(Unmount):组件从DOM树中被移除的过程

4.3.1 挂载阶段

constructor

组件的构造函数,第一个被执行,若没有显示定义它,会有一个默认的构造函数,但是若显示定义了构造函数,必须在构造函数中执行super(props),否则无法在构造函数中拿到this。
consturctor中通常只做两件事:

  • 初始化组件的state
  • 给事件处理方法绑定this
constructor(props) {super(props);// 不要在构造函数中调用 setState,可以直接给 state 设置初始值this.state = { counter: 0 }this.handleClick = this.handleClick.bind(this)
}
getDerviedStateFromProps

这是个静态方法,不能在这个函数里使用this,有两个参数props和state,分别指接受到的新参数和当前组件的state对象。这个函数会返回一个对象来更新当前的state对象,如果不需要可以返回null。

// 当 props.counter 变化时,赋值给 state 
class App extends React.Component {constructor(props) {super(props)this.state = {counter: 0}}static getDerivedStateFromProps(props, state) {if (props.counter !== state.counter) {return {counter: props.counter}}return null}handleClick = () => {this.setState({counter: this.state.counter + 1})}render() {return (<div><h1 onClick={this.handleClick}>Hello, world!{this.state.counter}</h1></div>)}
}

现在可以显示传入counter,但是如果想通过点击实现state.counter的增加,会发现值不会发生任何变化,一直保持props传进来的值。这是由于React16.4^版本中,setState和forceUpdate也会触发这个生命周期,所以当组件内部state变化后,就会重新走这个方法,同时把state赋值为props的值。解决:需要多加一个字段来记录之前的props值,这样就会解决上述问题,代码如下:

// 这里只列出需要变化的地方
class App extends React.Component {constructor(props) {super(props)this.state = {// 增加一个 preCounter 来记录之前的 props 传来的值preCounter: 0,counter: 0}}static getDerivedStateFromProps(props, state) {// 跟 state.preCounter 进行比较if (props.counter !== state.preCounter) {return {counter: props.counter,preCounter: props.counter}}return null}handleClick = () => {this.setState({counter: this.state.counter + 1})}render() {return (<div><h1 onClick={this.handleClick}>Hello, world!{this.state.counter}</h1></div>)}
}
render
  • 返回一个虚拟DOM,会被挂载到虚拟DOM树中,最终渲染到真实DOM中
  • render可能不只运行一次,只要需要重新渲染,就会重新运行
  • 严禁使用setState,因为可能会导致无限递归渲染
  • 可以返回布尔值或null 控制组件不渲染任何内容
componentDidMount()
  • 执行依赖于DOM的操作
  • 发送网络请求(官方建议)
  • 添加订阅消息(会在componentWillUnmount取消订阅)

如果在componentDidMount中调用setState,就会出发一次额外的渲染,多调用一次render函数。由于它是在浏览器刷新屏幕前执行的,所以用户是没有感知的,但是我们应该避免这样使用,这样会带来一定的性能问题,尽量在constructor中初始化state对象。

4.3.2 组件更新阶段

当组件的props改变了,或者组件内部调用了steState/forceUpdate,会触发更新重新渲染,这个过程可能会发生多次。这个过程会依次调用下面方法:

  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • getSnapshotBeforeUpdate
  • componentDidUpdate
shouldComponentUpdate
  • 指示react是否要重新渲染该组件,通过返回true和fasle来指定
  • 默认情况下,会直接返回true

可以比较 this.props 和 nextProps ,this.state 和 nextState 值是否变化,来确认返回 true 或者 false。当返回 false 时,组件的更新过程停止,后续的 render、componentDidUpdate 也不会被调用。
在这里插入图片描述

getSnapshotBeforeUpdate
//prevProps prevState:更新之前的props和state 
getSnapshotBeforeUpdate(prevProps, prevState)
  • 这个方法执行在rendr之后,componentDidUpdate之前(真实的DOM构建完成,但还未实际渲染到页面中)
  • 该函数的返回值,会作为componentDidUpdate的第三个参数
  • 在该函数中,通常用于实现一些附加的dom操作
    在这里插入图片描述
componentDidUpdate
// prevProps: 更新前的props
// prevState: 更新前的state
// snapshot: getSnapshotBeforeUpdate()生命周期的返回值
componentDidUpdate(prevProps, prevState, snapshot){}
  • 首次渲染不会执行此方法,更新后会被立即调用
  • 往往在该函数中使用dom操作,改变元素(也可以在此进行网络请求,例如:当props未发生变化时,则不执行网络请求)

4.3.3 组件卸载阶段

componentWillUnmount
  • 一个组件被卸载和销毁之前被调用
  • 清除 timer,取消网络请求或清除
  • 取消在 componentDidMount() 中创建的订阅等
  • 不应该在使用setState,因为组件一旦卸载,就不会装载也不会渲染

http://www.ppmy.cn/news/781.html

相关文章

MySQL介绍与安装(超详细)

数据库介绍 数据库(database)简称DB&#xff0c;实际上就是一个文件集合&#xff0c;是一个存储数据的仓库&#xff0c;本质就是一个文件系统&#xff0c;数据库是按照特定的格式把数据存储起来&#xff0c;用户可以对存储的数据进行增删改查等操作。 数据库存储数据特点 ●…

Java处理数据成为树状结构

如题所示&#xff0c;项目中需要将部分数据处理成为树状结构&#xff0c;实现过程如下&#xff1a; 注&#xff1a;也可以使用sql达到该目的&#xff0c;但此处数据不多&#xff0c;故在代码中处理&#xff0c;主要是sql处理不是很会 // 获取需要封装的数据List<Data> d…

java(面向对象)的23种设计模式(11)——观察者模式

一、定义 观察者模式&#xff1a;指多个对象间存在一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 换种说法&#xff0c;定义两种对象&#xff0c;观察者和目标对象&#xff0c;多个观察者同时监听一个目标对…

pikachu平台SQL注入

pikachu平台SQL注入 日常心累、速通pikachu注入相关 目录pikachu平台SQL注入使用到的名词解释1. 数字型注入 --使用bp处理数据包2. 字符型注入 --hackbar处理3. 搜索型注入4. xx型注入5. insert/update注入6. delete注入7. http头注入8. 布尔盲注9. 时间盲注10. 宽字节注入使用…

Shell基础语法——命令

内建命令&#xff08;内置命令&#xff09; 所谓 Shell 内建命令&#xff0c;就是由 Bash 自身提供的命令&#xff0c;而不是文件系统中的某个可执行文件。可以使用 type 来确定一个命令是否是内建命令。 通常来说&#xff0c;内建命令会比外部命令执行得更快&#xff0c;执行…

【云原生之Docker实战】使用docker部署Homebox内网测速工具

【云原生之Docker实战】使用docker部署Homebox内网测速工具 一、Homebox介绍1.Homebox简介2.Homebox特点二、检查本地系统环境1.检查系统版本2.检查系统内核版本三、检查docker环境1.检查docker版本2.检查docker状态四、下载Homebox镜像五、安装docker-compose工具1.下载docker…

qt程序的CMakeLists.txt配置转为平台的qt的.pro项目工程文件

参考这个 跨平台qt程序的CMakeLists.txt配置转为平台的qt的.pro项目工程文件_谁能懂我2011的博客-CSDN博客 一些比较正规的跨平台qt项目没有.pro项目文件只有CMakeLists.txt文件&#xff0c;如果要编译调试的话得转为qt项目&#xff0c; 首先打开qt安装目录里面的qmake工具&a…

leetcode 376 摆动序列

题目 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。 例如&#xff0c; [1, 7, 4, 9, 2, 5] 是一个 摆动序列…