React复习全攻略:重温旧知,收获新知

news2024/10/6 22:30:11

未命名图片 (1).jpeg

简介

大背景

  • 起源于 Facebook 的内部项目,因为对市面上所有JS MVC框架不满意,就自己开发了一套,用来开发Instagram项目。(开源时间:2013年5月)

三句话解释

  • 是用于构建 Web 和原生交互界面的库。
  • 是由各种组件,组成页面。
  • 是用于构建UI,专注于视图层的JS框架

主要特点

  • 组件化编码
    • 具有更强的复用性,维护性、扩展性
  • 高效(Diff算法):
    • 使用虚拟(Virtual)DOM,提升渲染性能
    • 使用Diff算法,提升更新效率
  • 单向数据流
    • 助于简化数据的管理和维护, 提高代码的可维护性和可预测性
  • JSX
    • JavaScript 的语法扩展(JavaScript XML)
    • 逻辑与UI耦合,采取组件单元,实现关注点分离

下面,我们再来与Vue进行对比,更为深入地了解React的特点

React Vue 异同处

相同点

  • 都有 虚拟Dom + Diff算法 的渲染机制,用于提升渲染速度
  • 都使用 组件化开发,通过props传参等方式进行父子数据通信
  • 都具备 状态管理(Vue的Vuex/Pinia,React的Redux/Mobx)
  • 都支持 跨平台开发(Vue的Uniapp,React的React Native)

不同点

框架层面

  • Vue
    • 本质属于MVVM模式(由MVC发展出来的)
    • 由于MVVM模式,双向数据流
  • React
    • 严格意义上,只能算是MVC中的View层
    • 由于MVC模式,单向数据流

数据层面

  • Vue
    • vue推崇响应式,实现了数据的 双向绑定
    • 由于数据可变,当数据发生变化,可通过 getter/setter 以及一些 函数的劫持监听数据的变化
    • 并且当数据变化时,可直接更新到对应的虚拟Dom(VM的理念)
  • React
    • React推崇 不可变(Immutable),为 单向数据流
    • 由于数据不可变,所以React无需监听数据的变化,React只对setState之后会有重新渲染的流程
    • 当数据发生变化(setState之后),React默认是通过比较 引用的方式(Diff) 进行的,所以若是不优化,则会导致大量非必要渲染,从而影响性能(代码要求更高)

渲染层面

  • Vue
    • Vue可以很快的计算出虚拟DOM的差异,这由于它监听了每一个组件的依赖关系,不需要重新渲染整个组件树
  • React
    • React数据变化时,会将全部子组件重新渲染。但可 shouldComponentUpdate 这个生命周期函数进行控制。

Diff 算法

  • Vue
    • 同层比较新老:新的不存在旧的存在就删除,新的存在旧的不存在就创建
    • 基于Snabbdom库,使用双向链表,边对比,边更新DOM
  • React
    • 递归同层比较,标识差异点保存到Diff队列,从而得到patch树,再统一操作批量更新DOM

其他层面

  • 模板语法不同:Vue是指令+模板语法,react是函数式编程
  • 性能优化可控:Vue性能优化(自动的)相对React可控性低,因此大型应用,数据量庞大,无需过量非必要的Watcher,出于性能方面,推荐使用可控的React。
  • 社区生态差异:Vue国内受众人群多,React国际受众人群多(更为成熟↑)

核心

接下来,我们继续来了解React的核心内容:

  • JSX语法:嵌入绑定、条件渲染、列表渲染
  • 组件化:组件分类、组件生命周期、组件通信
  • Hooks:useState、useEffect、useContext、useReducer、useRef、useMemo、useCallBack

JSX语法

我们在简介里,已经了解到,JSX全称为JavaScript XML,是JavaScript的一种语法扩展。本质是 React.createElement 的语法糖,即创建虚拟DOM的方法

解决痛点为了简化创建虚拟DOM,无需每次嵌套使用 React.createElement。

简易写法:

const element = <h1>Hellow World!!!<h1/>

语法规范

  • JSX只能有一个根标签
  • 标签使用变量(JS表达式),用大括号{}包起来
  • 类名class,变className使用
  • 内联样式,使用键值对写法,例如style={{color:‘#fff’}}
  • 标签首字母
    • 小写字母开头:html标签
    • 大写字母开头:JSX组件

简易例子

const MyComponent = () => {
    const divStyle = {
        color: 'blue',
        backgroundColor: 'yellow',
        padding: '10px',
        border: '1px solid black'
    };

    return (
      <>
        <div className="divClass">外链样式</div>
        <div style={divStyle}>内嵌样式</div>
      </>
    );
};

export default MyComponent;

嵌入绑定

JSX可嵌入变量和表达式(运算符、函数调用),绑定属性和方法

import React, { useState } from 'react';  

const MyComponent = () => {
  // 嵌入变量  
  const name = 'React Developer';  
  const age = 25;  
  
  // 使用useState来管理一个状态变量  
  const [visible, setVisible] = useState(true);  
  
  // 嵌入表达式 - 函数调用(例如,计算年龄的平方)  
  const ageSquared = () => age * age; 
  
  const handleClick = () => {
      setVisible(!visible);  
  }
  
  return (  
    <>  
      {/* 嵌入变量 */}  
      <p>Name: {name}</p>  
      <p>Age: {age}</p>  
  
      {/* 嵌入表达式 - 运算符 */}  
      <p>Age Squared: {age * age}</p>
      {/* 嵌入表达式 - 三元 */}
      <p>Is Age Blow 20: {age < 20 ? 'Yes' : 'No'}</p>
      {/* 嵌入表达式 - 函数调用 */}
      <p>Age Squared: {ageSquared()}</p>
      
      {/* 绑定属性(事件处理器) */}  
      <button onClick={handleClick}>  
        {visible ? 'Hide' : 'Show'}  
      </button>
    </>  
  );  
}  
  
export default MyComponent;

条件渲染

常见的条件渲染,有以下三种方式:

  • 方法1:条件函数判断:适合逻辑多,拆解成函数,进行if,switch 或策略模式
  • 方法2:三元运算符:适合逻辑简单的,最好就单层。
  • 方法3:与运算符&&:条件成立渲染后面的标签或组件。
import React, { useState } from 'react'; 
import Admin from './Admin'; // 假设Admin组件在'./Admin'文件中

const MyComponent = () => {
  const [userRole, setUserRole] = useState(1);
  
  const changeUserRole = (role) => {
      setUserRole(role === 1 ? 2 : 1)
  }
  
  // 函数条件判断
  const roleComponents = () => {
      if(userRole === 1) return <Admin />
      else return null;
  }
  
  return (
     <>
       <button onClick={changeUserRole}>切换身份</button>  
       {/* 条件函数 */} 
       {roleComponents()}
       {/* 三元运算 */} 
       {role === 1 ? <Admin /> : null}
       {/* 与运算 */} 
       {role === 1 && <Admin />}
     </>
  )
}

export default MyComponent;

列表渲染

我们一般使用 map函数 来遍历数组,如下面的代码所示:

function MyComponent() {  
  const lists = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];  
  
  return (  
    <>  
      <h1>Fruit List</h1>  
      <ul>  
        {lists.map((item, index) => (  
          <li key={index}>{item}</li>  
        ))}  
      </ul>  
    </>  
  );  
}  
  
export default MyComponent;

注:key 和 React 中的 Diff 算法密切相关。所以我们需要给每个map列表循环加上key值。
不然会报错:warning: Each child in a list should have a unique “key” prop.


组件化

组件化是一种高效的处理复杂应用系统,更好的明确功能模块作用的方式。即为一种分而治之的思想。

而React整个框架都围绕着组件化这一核心概念展开,可以说组件化是React的核心思想

  • 组件是构建用户界面的基本单元
  • React组件可以分为两类:类组件函数组件
  • 组件化的好处:提高代码的可维护性、以及可复用性(提效)

类组件

React一开始,以类组件作为主体,在React16.8版本(引入React Hooks)后,解决了类组件的部分痛点(Hooks部分再说明),函数组件后来者居上。

定义特点

  • 组件首字母大写
  • 继承自React.Component
  • 必须实现render函数

实现方式

  • 使用ES6 Class语法
  • 构造器是可选的,用于初始化数据
import React, { Component } from 'react';
 
export default class App extends Component {
  constructor() {
    super();
    this.state = {};
  }
 
  render() {
    return (
      <div>
        <h1>我是类组件</h1>
      </div>
    );
  }
}

函数组件

函数组件,字面意思,就是JavaSript函数作为React组件。

定义特点

  • 组件首字母大写
  • 无生命周期函数,可用useEffect替代
  • 无状态管理,可用useState替代
// 定义一个函数组件  
function Greeting({ name }) {  
  // 使用JSX来渲染组件的UI  
  return (  
    <div>  
      Hello, {name}!  
    </div>  
  );  
}  
  
// 在另一个组件或应用中使用Greeting组件  
function App() {  
  return (  
    <div className="App">  
      <Greeting name="Alice" />  
      <Greeting name="Bob" />  
    </div>  
  );  
}  
  
export default App;

生命周期

生命周期,指的是一个组件从其创建到销毁的整个过程。(React里面,只有类组件有,函数组件没有生命周期)

在这个过程中,React为组件划分了多个不同的阶段,每个阶段都配备了专门的方法和用途。正确理解和运用React的生命周期,对于构建既稳定又易于维护的React应用来说,显得至关重要。

掌握并恰当应用这些生命周期方法,将使得我们的React应用更加健壮和高效。

下面是最新16.3版本后的生命周期函数:

e4fe31797a6b417baaf7ff25044ea570.webp


挂载时

挂载时,是指组件实例被创建,首次插入到页面的过程。主要涉及到四个方法:constructorrendercomponentDidMount,还有16.3新增的 getDerivedStateFromProps

以下是使用这些方法的示例:

class MyComponent extends React.Component {  
  constructor(props) {  
    super(props);  
    // 1、初始化state  
    this.state = {  
      data: props.initialData, // 假设从props中接收initialData  
    };  
  }  
  
  // 2、静态方法
  static getDerivedStateFromProps(props, state) {  
    // 当props变化时,根据新的props和当前的state更新state  
    if (props.initialData !== state.data) {  
      return {  
        data: props.initialData,  
      };  
    }  
    // 如果没有变化,返回null表示不更新state  
    return null;  
  }  
  
  componentDidMount() {  
    // 3、组件挂载到DOM后执行,适合发起网络请求、订阅事件等操作  
    console.log('Component has been mounted!');  
  }  
  
  render() {  
    // 4、渲染组件  
    return (  
      <div>  
        <h1>My Component</h1>  
        <p>Data: {this.state.data}</p>  
      </div>  
    );  
  }  
}  

export default MyComponent;

以上例子,总结:

  • constructor(props):方法用于初始化组件的state,并绑定事件处理函数到组件实例上。
  • getDerivedStateFromProps:是一个静态方法,它在每次组件的props更新并且即将重新渲染前被调用。
  • render:用于渲染组件的UI。
  • componentDidMount:在组件挂载到DOM后立即执行。

更新时

当React组件的props或state发生变化时,组件会经历更新阶段。在更新阶段,React会根据这些变化决定是否重新渲染组件,并调用相应的生命周期方法。

主要涉及这几个方法:getDerivedStateFromPropsshouldComponentUpdategetSnapshotBeforeUpdatecomponentDidUpdate

以下是一个例子,说明了React组件在更新时涉及的主要生命周期方法:

class MyComponent extends Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      count: 0,  
      prevCount: null,  
    };  
  }  
  
  static getDerivedStateFromProps(props, state) {  
    // 根据props更新state,比如初始化state或者响应props的变化  
    if (props.initialCount !== state.count) {  
      return {  
        count: props.initialCount,  
        prevCount: state.count,  
      };  
    }  
    return null;  
  }  
  
  shouldComponentUpdate(nextProps, nextState) {  
    // 根据props或state的变化来决定是否重新渲染组件  
    // 这里我们简单地比较count是否变化  
    return nextState.count !== this.state.count;  
  }  
  
  getSnapshotBeforeUpdate(prevProps, prevState) {  
    // 在DOM更新之前获取一些信息  
    // 假设我们要获取滚动位置  
    const scrollPosition = this.listRef.scrollTop;  
    return {  
      scrollPosition,  
    };  
  }  
  
  componentDidUpdate(prevProps, prevState, snapshot) {  
    // DOM更新后,使用snapshot中的信息  
    if (snapshot && snapshot.scrollPosition !== undefined) {  
      this.listRef.scrollTop = snapshot.scrollPosition;  
    }  
  
    // 假设我们还需要比较prevCount和currentCount  
    if (prevState.prevCount !== null && prevState.prevCount !== this.state.count) {  
      console.log(`Count changed from ${prevState.prevCount} to ${this.state.count}`);  
    }  
  }  
  
  handleIncrement = () => {  
    this.setState((prevState) => ({  
      count: prevState.count + 1,  
      prevCount: prevState.count,  
    }));  
  };  
  
  render() {  
    return (  
      <div>  
        <p>Count: {this.state.count}</p>  
        <button onClick={this.handleIncrement}>Increment</button>  
        <div  
          ref={(element) => (this.listRef = element)}  
          style={{ height: '200px', overflowY: 'scroll' }}  
        >  
          {/* Some long content here that causes scrolling */}  
        </div>  
      </div>  
    );  
  }  
}  
  
export default MyComponent;

以上例子,总结:

  • getDerivedStateFromProps 用于根据传入的props(initialCount)来初始化或更新组件的state。如果initialCount与当前count不同,它会返回一个新的state对象,其中包含更新后的 count 和旧的 count 值(prevCount)。
  • shouldComponentUpdate 是一个方法,用于根据props或state的变化来决定是否重新渲染组件。这里我们简单地比较了 nextState.countthis.state.count,如果它们不同,则组件会重新渲染。
  • getSnapshotBeforeUpdate 在DOM更新之前被调用,它返回一个对象,该对象在 componentDidUpdate 的第三个参数中可用。这里我们获取了滚动列表的滚动位置。
  • componentDidUpdate 在组件更新后被调用,并且接收上一个props、上一个state和getSnapshotBeforeUpdate 返回的snapshot作为参数。我们使用snapshot中的滚动位置来恢复滚动位置,同时比较 prevCountthis.state.count 来记录变化。

卸载时

卸载时阶段指的是组件从DOM中被完全移除时。

例如在类组件中,componentWillUnmount 是一个在组件卸载及销毁之前直接调用的生命周期方法。你可以在这个方法中执行任何必要的清理操作,例如取消网络请求、清除定时器、解除事件监听器等。

class MyComponent extends React.Component {  
  componentDidMount() {  
    // 设置定时器  
    this.timer = setInterval(() => {  
      console.log('This runs every second');  
    }, 1000);  
  }  
  
  componentWillUnmount() {  
    // 清除定时器  
    clearInterval(this.timer);  
  }  
  
  render() {  
    return <div>MyComponent</div>;  
  }  
}

export default MyComponent;

在上面的例子中,componentDidMount 中设置了一个定时器,而 componentWillUnmount 中则清除了这个定时器,以确保在组件卸载时不会继续执行定时器的回调。


Hooks 放下一篇文章里,这里字已经水的差不多了😀

总结

温故而知新,可以为师矣~

重温React,不仅是对知识的回顾,更是对技术的敬畏和热爱。感谢React带给我们的每一次成长与收获,期待在未来的开发中,我们能与React一起创造更多的奇迹。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1577721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MWeb Pro For Mac v4.5.9 强大的 Markdown 软件中文版

MWeb 是专业的 Markdown 写作、记笔记、静态博客生成软件&#xff0c;目前已支持 Mac&#xff0c;iPad 和 iPhone。MWeb 有以下特色&#xff1a; 软件下载&#xff1a;MWeb Pro For Mac v4.5.9 软件本身&#xff1a; 使用原生的 macOS 技术打造&#xff0c;追求与系统的完美结合…

OpenImageDebugger - CLion研究

在windows下有vistual studio&#xff0c;针对opencv有image watch&#xff0c;在ubuntu下用Clion插件Image Watch要收费&#xff0c;遂研究OpenImageDebugger与CLion问题&#xff0c;还有些未研究透彻&#xff0c;先记录当前部分。 Open Image Debugger Open Image Debugger …

Linux文件IO(4):目录操作和文件属性获取

目录 1. 前言 2. 函数介绍 2.1 访问目录 – opendir 2.2 访问目录 – readdir 2.3 访问目录 – closedir 2.4 修改文件访问权限 – chmod/fchmod 2.5 获取文件属性 – stat/lstat/fstat 2.5.1 文件属性 – struct stat 2.6 文件类型 – st_mode 3. 代码练习 3.1 要求 3.2 代…

深度挖掘商品信息,jd.item_get API助您呈现商品全面规格参数

深度挖掘商品信息&#xff0c;特别是在电商平台上&#xff0c;对于商家、开发者和用户来说都至关重要。jd.item_get API作为京东开放平台提供的一个强大工具&#xff0c;能够帮助用户轻松获取商品的全面规格参数&#xff0c;进而为商品分析、推荐、比较等提供有力的数据支撑。 …

灵猫论文靠谱不 #职场发展#职场发展

对于许多学生和研究人员来说&#xff0c;写论文是一个耗时且具有挑战性的任务。在撰写论文的过程中&#xff0c;除了要进行繁琐的写作工作外&#xff0c;还需要花费大量时间来查找资料、整理文献、检查语法和格式等。为了帮助大家轻松完成论文写作&#xff0c;现在有了许多写作…

【QT入门】Qt自定义控件与样式设计之QPushButton常用qss

往期回顾 【QT入门】Qt自定义控件与样式设计之qss介绍(Qt style sheet)-CSDN博客 【QT入门】 Qt自定义控件与样式设计之qss选择器-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QLineEdit的qss使用-CSDN博客 【QT入门】Qt自定义控件与样式设计之QPushButton常用qss 这里我们主…

本地电脑渲染不行怎么解决?自助式渲染助你渲染无忧

有时候&#xff0c;即使购买了昂贵的新电脑&#xff0c;我们也可能会遇到渲染速度缓慢、画质不佳或渲染失败等问题。这些问题可能由多种因素引起。针对该问题&#xff0c;为大家推荐了自助式的渲染&#xff0c;解决你本地电脑渲染不佳问题。 电脑渲染不行原因 新电脑渲染效果不…

亚马逊AWS上怎么创建Linux 服务器?操作难不难?

AWS(Amazon Web Services)是全球领先的云服务器提供商之一。你可以使用 AWS 平台在一分钟内设置完服务器。在 AWS 上&#xff0c;你可以微调服务器的许多技术细节&#xff0c;如 CPU 数量&#xff0c;内存和磁盘空间&#xff0c;磁盘类型(更快的 SSD 或者经典的 IDE)等。关于 A…

【linux】set ff=unix、linux设置文件格式

文章目录 一、文件格式二、如何查看文件格式三、设置文件格式、set ffunix四、查看unix与dos的区别 一、文件格式 当我们打开sh脚本时发现有时候格式是unix(LF) ,有时候是windows(CR LF) 。如下图&#xff1a; 文件格式影响了文件中的换行符 linux中sh类型的文件一般要设置为…

测试必备:网站崩溃原因大揭秘!12种常见问题一网打尽

网站崩溃是研发团队最怕看到的情况&#xff0c;但是由于种种原因却时常出现&#xff0c;作为测试人员&#xff0c;我们更应该比一般人了解网站崩溃的原因及排查方法&#xff0c;这是我们测试工作的重要一环。接下来我就谈谈12种常见的网站崩溃原因以及如何跟踪和解决它们。 你的…

纯小白蓝桥杯备赛笔记--DAY10(字符串)

文章目录 KMP字符串哈希算法简介&#xff1a;斤斤计较的小z--2047字符串hash Manacher回文串的性质算法简介最长回文子串 字典树基础朴素字符串查找步骤前缀判定--1204 01tire算法简介&#xff1a;例题1&#xff1a;例题2&#xff1a; KMP字符串哈希 算法简介&#xff1a; 真前…

js将对象数组中的某个属性值,批量替换成另一个数值

前提&#xff1a;对接口数据进行替换。把对应的数值或者字符串替换成中文。。。 核心代码&#xff1a; const toStr {sh: "沪",sz: "深", };myArr.map((item) > {const placeCode item.placeCode;item.placeCode toStr[placeCode] ? toStr[placeC…

Xshell连接不上Ubuntu

1 ubuntu安装ssh服务器 sudo apt install openssh-server修改配置文件vi /etc/ssh/sshd_config 修改如下两个配置 修改完运行下面代码。再用 xhell连接试试。 /etc/init.d/ssh restart

普通相机标定——执行与结果验证

在之前的准备工作中,我们完成了 棋盘格标靶的制作采集相机图像功能函数的实现相机内参标定功能函数实现工具类函数的实现 终于到了将他们组合起来实现相机内参标定的时刻了!这里作者用的是笔记本电脑的前置相机,首先调用SaveCameraImage()保存相机图像,同时手举棋盘…

搜维尔科技:一个人如何使用Faceware为歌手制作完整的MV

一个人如何使用Faceware为歌手制作完整的MV 最近&#xff0c;我们有机会采访了 Bryce&#xff0c;他是一位独立创作者&#xff0c;他通过使用 Faceware 来制作视频。完整采访如下&#xff1a; 这个项目是如何产生的&#xff1f;该项目的推动力是什么&#xff1f; “我爱你”M…

字节出来的,太厉害了。。。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前段时间公司缺人&#xff0c;也面了许多测试&#xff0c;一开始…

【UE 网络】DS框架学习路线

目录 0 引言1 如何学习DS框架1. 熟悉Unreal Engine基础2. 学习网络编程基础3. 掌握UE网络概念4. 实践和实验5. 加入社区和论坛6. 官方示例和案例研究7. 专业书籍和在线课程 2 DS框架重要知识点有哪些1. 网络复制2. 远程过程调用&#xff08;RPC&#xff09;3. 客户端服务器架构…

RabbitMQ基本使用及企业开发中注意事项

目录 一、基本使用 二、使用注意事项 1. 生产者重连机制 - 保证mq服务是通的 2. 生产者确认机制 - 回调机制 3. MQ的可靠性 4. Lazy Queue模式 5. 消费者确认机制 一、基本使用 部署完RabbitMQ有两种使用方式&#xff1a; 网页客户端Java代码 MQ组成部分&#xff1a;…

【php开发支付宝web支付】

首先介绍下 我用的框架ci 在吐槽下百度的其他人的写的都很垃圾&#xff0c;还不如自己看支付宝的开发手册了 1、composer安装支付宝的sdk composer require alipay/alipay-sdk-php安装完毕 不多哔哔 代码展示 先点地址登录支付宝以后再上我这重点下 支付宝沙箱地址 $ord…

easyexcel处理复杂表头

需求&#xff0c;模板如下 功能如下 开始整活&#xff0c;依赖包。 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version> </dependency>下载导入模板 1.方法 GetMapping…