likes
comments
collection
share

Intro to React

作者站长头像
站长
· 阅读数 61

前端历史

在讲react之前,我们先用十几分钟的时间回顾下前端的发展史,这更有利于我们理解react的产生背景和目前流行的原因

洪荒时期

Intro to React 如图所示,早期的浏览器非常简陋,1995年JavaScript刚建立的时候,页面是没有状态的,此时一个网页的开发遵循后端为主的MVC模式,后端负责保存和管理数据(Model),处理数据,实现业务逻辑(Control),而前端只负责写网站视图层的模板代码(View),此时确实非常符合切图仔的说法,如果大家了解php和jsp的话,肯定能理解以下两个图例。

Intro to React php

Intro to React

jsp

Ajax的出现

之前前后端不分离技术的痛点

  1. 用户体验不流畅
    • 每次操作都要刷新页面获取新的状态,体验割裂
  2. 页面加载速度慢
    • 每次刷新页面会导致资源重新请求加载,增加加载时间
  3. 前后端协作困难

举个例子:在用户书写表单的这种情况下,每次提交都要刷新页面,然后在新的页面告诉你成功/失败的状态,如果网速慢或者其他原因,就会导致404,从头重新填写数据,用户体验非常糟糕。

Ajax技术的出现后改变了这个局面,Ajax可以做到在不刷新页面状态,向后端请求数据,更新部分网页,在用户体验上比之前是质的飞跃。这时逐渐前端开始保存一些状态,通过Ajax获取数据后实现某些交互,前后端分离的开发模式雏形开始出现。

但是在这时也存在一些问题,各个浏览器的语法不统一,为了实现交互前端要频繁的进行dom操作,用原生js处理这些问题时颇为麻烦,业界急需一个统一的前端跨浏览器处理方案

jQuery应时而生

前文我们讲了,当时前端有两个痛点

  • 缺乏一个完善的跨浏览器处理方案
  • 缺乏简单的处理dom、事件操作的函数库

时势造英雄,为了解决这些问题,层出不穷的出现了许多函数库解决方案,在众多解决方案之中,一个名叫jQuery的函数库最为亮眼,解决了以上两个问题,还以简单的写法在全球前端中风靡。

依赖jQuery,前端写代码难度大大下降

举个例子:点击图片隐藏

<button id="button">点击我</button>
<img id="image" src="xxx.jpg">

原生代码:

var button = document.getElementById("button"),
    image = document.getElementById("image")

button.onclick = function() {
    image.style.display = "none";
};

jQuery:

$("button").onclick = function() {
    $("image").style.display = "none";
};

现代框架

随着jQuery的流行,前端开发在网页开发中的话语权逐渐上升,前端自己维护页面状态,通过jQuery修改dom元素和事件完成交互,通过Ajax实现和后端的数据交流。前端开发向着好的流程前进。

但是在逐渐成熟之后,前端们发现目前的前端技术栈不太满足模块化、协作化的趋势,而且前端需要一个全面的方案来迎合新的开发思想:MVC、MVVM,这种数据和视图分离的思想有助于降低耦合性,增加复用性。同时,如何维护网页中越来越多的状态也成为了衡量前端开发能力的表现。

种种原因之下,前端开发进入下一个阶段水到渠成

在三大框架之前,在模板引擎的设计思想上得到了启发,前端也做了非常多的尝试比如

  • Backbone.js
  • Ember.js
  • AngularJS
  • Knockout.js

这些框架解决了部分问题,迎合了MVC模型,但是又不够好用。

最终,大家众所周知的三大框架站上了时代舞台

  • React.js
  • Angular
  • Vue.js

也成为了现代前端开发的流行框架

未来的趋势

在以上技术的加持以及JavaScript技术更新之后,前端的能力越来越广,前端涉足的业务也越来越多

  • 游戏开发(coco2d-js,白鹭)
  • webApp开发(flutter RN weex ionic)
  • 图形开发WebGl(three.js)
  • 小程序/快应用
  • 后端(nodejs)
  • 桌面应用(electron)
  • 嵌入式开发(Ruff)
  • Web3开发(viem、wagmi)

而为了提高前端的开发体验,配套的开发配件也发展越来越快

  • TypeScript 解决类型问题增加鲁棒性
  • Webpack、Vite 解决了打包问题
  • Next、Nuxt 提供了全面能力的前端框架

未来前端,或者说大前端会有更多想象空间

前面讲了很久,想必大家对过去二三十年前端的发展有了一个初步的认识,那么我们现在进入正题,了解下什么是React、以及React的优劣势,包括React在web3的应用

关于React

React是什么

React是Meta2013年推出的内部使用的前端框架,是目前使用人数最多的前端框架,拥有最好的社区支持和生态圈以及大量的第三方工具,在海外占比最高

React开发思想

我个人理解,React开发的思想是拆解、抽象、封装、组合

React团队推荐开发者把一个⼤需求拆解,使⽤ JSX 语法编写粒度小的可复用性的组件合成需要的用户页面,开发者只需要考虑如何拆解复用组件,管理每个组件的状态。而无需考虑整体的复杂情况

React解决了什么问题

在吹逼优点之前,我们不妨了解下React解决了哪些我们上面提到的的问题

  • 使用虚拟DOM和声明式编程,解决了jQuery仍需要手动操作DOM的问题
  • 通过单向数据流的思想简化了数据管理的复杂度,易于理解和维护
  • 引入组件化开发模式,满足前端工程化和模块化的趋势
  • 可以使用React Native来实现跨平台开发

React的优点

vs vanilla.js

  1. 引入组件化开发

    拆解需求,把大化小,把一个页面拆解成一个个小组件,只需要维护每个小组件的功能,整个成一个页面。方便维护、开发、复用 Intro to React

  2. 使用声明式编程和虚拟DOM技术

    代码编写简单,只需要描述你想要的 UI 结果,而不需要手动操作 DOM。这样可以使代码更加简洁、清晰、易于维护。⽆需考虑实际处理

    在这个例子里,我们生成了一个组件,自动接收tasks数据直接会生成对应的代码,而不需要在内部详细描述接收props之后怎么处理生成对应的代码

    import React from 'react';
    
    interface Task {
      id: number;
      title: string;
    }
    
    interface TaskListProps {
      tasks: Task[];
    }
    
    // 声明式编程:将任务列表数据作为 props 传递
    const TaskList: React.FC<TaskListProps> = ({ tasks }) => (
      <div>
        <h1>任务列表</h1>
        <ul>
          {tasks.map(task => (
            <li key={task.id}>{task.title}</li>
          ))}
        </ul>
      </div>
    );
    
    export default TaskList;
    
  3. 单向数据流

    单向数据流的使用使得数据是可预测,可追溯的,容易管理状态

  4. 跨平台兼容性

    可以用同样的语法使用React Native写移动端代码

  5. 灵活的状态管理机制

    使用开源的Redux、Mobx、zustand等库更方便管理每个组件的状态

vs 其他框架

  1. 海外市场占比最高,岗位最多

Intro to React

  1. TypeScript支持好

    • 类型安全: TypeScript 是一种静态类型检查的语言,可以在编译时发现并修复许多常见的错误。在 React 项目中使用 TypeScript 可以帮助开发者捕获潜在的类型错误,减少在运行时出现的错误,提高代码的质量和稳定性。
    • 智能提示: 在使用 TypeScript 编写 React 代码时,编辑器(如 Visual Studio Code)可以根据类型信息提供智能提示和自动补全的功能,使得开发过程更加高效和流畅。开发者可以更快速地找到需要的属性和方法,减少编码时的猜测和查找时间。
    • 更好的代码维护性: TypeScript 的类型系统可以帮助开发者更好地理解和维护代码。类型定义可以作为代码的文档,帮助他人更快地理解代码的意图和用法。此外,当代码需要进行重构或修改时,类型检查器可以帮助开发者更容易地发现并修复相关的依赖项。
    • 更好的团队协作: 使用 TypeScript 编写 React 代码可以提高团队之间的协作效率。类型定义可以作为接口的约定,使得不同团队成员之间的代码更容易理解和集成。此外,类型检查器可以在代码提交前进行静态检查,避免将错误的代码合并到主分支中。
  2. 符合函数式编程思想

    React 的函数式编程范式使得组件更容易理解和测试,开发者可以使用纯函数和无状态组件来构建应用,从而使代码更加清晰和易于维护

  3. JSX 书写代码更简单,写法更⾃由,逻辑更直观,不需要强制使用模板

    • 易于理解和编写: JSX 结合了 JavaScript 和 HTML 的语法,使得开发者可以在 JavaScript 中直接编写类似 HTML 的代码,减少了学习新语法的成本,并使得代码更加易于理解和编写。
    • 直观的语法: JSX 的语法结构类似于 HTML,使得开发者可以直观地描述 UI 结构和样式。这种直观的语法使得开发者可以更快速地理解代码的意图,并且可以更容易地与设计师和其他团队成员进行沟通和合作。

React的缺点

  1. JSX太灵活,由于JSX 写法太过⾃由导致缺乏范式和最佳实践,学习曲线陡峭,学会react不难,但是写好代码很难
  2. 社区生态相对分散,react官方没有提供一套官方完整可⽤的套件,如 Vue-Router、 Vuex,必须引⼊社区的优秀包才能实现完全的router、状态管理等功能,需要花费更多的时间来评估和选择适合项目的第三方库和工具
  3. 简中学习材料不如 Vue 丰富,质量略差

React趣谈

仅个⼈看法:

由于 Meta裁员和员⼯跳槽,不少之前的核⼼ React 开发⼈员都跳槽到了 Vercel,现在官⽹已宣布停⽌维护 create react app,⽽且官⽹建议启动新 React项⽬时直接使⽤ Next.js 、 Remix 等框架,这些框架在 React 基础上增加了全⽅位的功能,⽐如⽀持 SSR 、 SSG ,⾃带 Router管理、 api 中间件控制等等功能。在使⽤时增加了学习成本,需要学习框架的新特性,新功能,新写法。相⽐下来,未来开发 React⽅向与 Vercel绑定过于密切,从⾯对⼴⼤开发转向⾯对开源组织,最新的特性很多都是 Next.js 转正,不得不引起一些槽点。

以上,我们简单了解了下React和vanilla.js以及其他框架对比下来的优势和劣势,相信对各位选型会有一些借鉴作用。接下来我们将具体了解下react的思想和特性,方便我们更了解react。

React的概念和特性

React学习了现代开发的很多优秀概念并且创造了很多自己的特性,接下来我们会把其中几个关键的概念简单讲解下,希望能帮助各位理解

⼋股时间

  1. 单向数据流
  2. 虚拟 DOM
  3. JSX 语法
  4. 声明式编程(函数式编程)
  5. React Hook

etc.

单向数据流

单向数据流是一种数据流动的模式,在这种模式下,数据在应用中的流动方向是单向的,通常是从父组件流向子组件,直接来说:只能通过 Actions修改 State,从⽽触发View更新,⽆法反向控制,⼦组件只能监听⽗组件传来的 props修改⾃⼰的state,⽆法直接修改父组件的数据

如下图所示

Intro to React 单向数据流有很多优点

  1. 可预测性: 单向数据流使得数据的流向更加清晰和可预测。数据只能从父组件流向子组件,子组件无法直接修改父组件的数据。这种模式降低了数据流动的复杂性,使得代码更容易理解和调试。
  2. 可维护性: 单向数据流降低了组件之间的耦合性,使得组件更加独立和可复用。每个组件只关注自己的数据和逻辑,不需要关心其他组件的状态。这样可以提高代码的可维护性,减少了代码的藕合度,使得代码更易于扩展和修改。
  3. 数据流动更可控: 在单向数据流模式下,数据的流动是可控的。数据的变化只能通过 props 从父组件传递给子组件,子组件通过回调函数将事件传递给父组件。这种数据流动模式使得数据的变化更加可控,减少了意外的数据变化,提高了代码的健壮性。
  4. 易于调试: 单向数据流使得代码的数据流动更加直观和清晰,易于调试。开发者可以更容易地追踪数据的变化路径,找到错误的根源。此外,由于数据流动的方向明确,可以更轻松地定位和修复问题。
  5. 性能优化: 单向数据流模式可以更容易地实现性能优化。由于数据流动的方向明确,开发者可以更精确地控制组件的渲染时机,避免不必要的渲染和更新,提高页面的性能和响应速度。

虚拟DOM

前面我们讲了jQuery只是优化了操作DOM的难度,没有解决前端开发如果遇到复杂交互需要非常多手动操作DOM的问题,而react提出了自己的虚拟DOM方法来解决这个问题

从核心来看,React的虚拟DOM是一个Object树,它对应着实际 DOM 中的结构。当数据发生变化时,React 不会直接操作实际的 DOM 元素,而是通过react fiber方法比较新旧虚拟 DOM 树的差异(称为协调或调和),然后只对变化的部分进行实际的 DOM 操作。这种方式可以减少不必要的 DOM 操作,从而提高了页面的渲染性能。我们以实际例子来认识一下这个概念

// JSX的写法
const element = (
  <div className='container'>
    <h1>Hello, World!</h1>
  </div>
);
// 等效React.createElement的写法
const elementReact = React.createElement(
  'div',
  { className: 'container' },
  React.createElement('h1', null, 'Hello, World!'),
);
// 实际存储的数据结构,React会用这个对象树来进行渲染
const virtualDOMTree = {
  type: 'div',
  props: {
    className: 'container',
    children: [
      {
        type: 'h1',
        props: {
          children: 'Hello, World!',
        },
      },
    ],
  },
};

其实这是一种空间换时间的做法,减少DOM的操作次数,从而提升性能,

优点:

  1. 跟原⽣ DOM 操作⽐提⾼效率,每次更新只需要局部更新,不需要每次改动都触发重绘和回流
  2. ⽤空间换时间,在牺牲了内存开销和初次渲染的性能的前提下,提高了渲染效率
  3. 增加了可维护性,代码简约,开发者不用考虑实际DOM操作,降低前端开发的难度

JSX

JSX是一种 JavaScript 的语法扩展,常用于描述 React 组件的 UI 结构。JSX 看起来像是 HTML,但实际上是 JavaScript 的一种语法糖,它允许在 JavaScript 中直接书写类似 HTML 的标签,并最终编译调用。

import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}

React17前会在babel下转化成

import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}

React17以后会转化成

// 由编译器引入(禁止自己引入!)
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

最终再利用虚拟DOM树渲染成需要的HTML内容

Hook

说实话,React Hook是最难讲的一部分,因为React Hook改变了之前我们写类组件的惯性思想,但是确实是未来趋势,请各位朋友以后直接编写函数式组件取代类组件

React Hook 是 React 16.8 引入的一种新特性,它允许在函数组件中使用状态和其他 React 特性,而不需要编写类组件。Hook 提供了一组函数,使得在函数组件中能够实现以前只能在类组件中使用的功能,比如管理状态、生命周期方法、上下文等。

他避免了类组件写起来复杂,生命周期繁多,还强制super,this管理困难的问题,同时也符合函数式编程的思想:

1. 纯函数和无副作用

函数式编程强调使用纯函数,即相同的输入总是产生相同的输出,并且没有副作用。React 函数组件和自定义 Hook 遵循这一原则:

  • 函数组件:React 函数组件通常是纯函数,根据输入的 props 生成相应的 UI。
  • 自定义 Hook:自定义 Hook 也可以设计为纯函数,通过参数控制其行为。

2. 不可变性

函数式编程鼓励不可变数据结构,即不直接修改数据,而是返回新的数据副本。React Hooks 中的 useStateuseReducer 都提倡这种模式:

  • useState:状态更新通过 setter 函数进行,每次更新都会创建新的状态值,而不是直接修改原来的状态。
  • useReducer:通过返回新的状态对象来更新状态,而不是直接修改现有状态。

3. 函数是一等公民

在函数式编程中,函数是一等公民,可以作为参数传递或作为返回值返回。React Hooks 提供了一种声明式的方式来使用函数,从而增强了代码的可组合性和重用性:

  • useCallbackuseMemo:这些 Hook 可以记忆化函数和计算结果,以优化性能。
  • 自定义 Hook:可以将重复的逻辑提取到自定义 Hook 中,方便在不同组件中复用

React Hook的优点

  1. 简化代码结构
    • Hook 使得函数组件能够拥有状态和其他 React 特性,避免了类组件中复杂的 this 绑定问题和冗长的代码结构。
  2. 提高代码复用性
    • 自定义 Hook 可以将组件逻辑提取到可复用的函数中,方便在不同组件之间共享逻辑。
  3. 更好的逻辑组织
    • 使用 Hook,可以将与特定逻辑相关的代码组织在一起,而不是分散在不同的生命周期方法中,使得代码更易读、更易维护。
  4. 避免类组件的缺陷
    • 减少了类组件中的样板代码(boilerplate),如构造函数、生命周期方法等,使得代码更加简洁。
    • 避免了 this 关键字的使用,使得代码更加直观和简洁。
  5. 轻量级和易测试
    • 函数组件通常比类组件更轻量级,更易于编写和测试。
  6. React 19会更新Hook的新特性,但是类组件没有同步更新
    • useOptimistic
    • useFormStatus

React Hook的缺点

  1. 学习曲线
    • 对于习惯了类组件的开发者,Hook 需要一些时间来学习和适应,特别是在理解 useEffect 和自定义 Hook 的用法时。
  2. 复杂度的提升
    • 在使用多个 Hook 时,特别是 useEffect,可能会导致代码变得复杂,难以调试和维护。
  3. 性能陷阱
    • 不当使用 useEffect、useCallback 和 useMemo 等 Hook 可能会导致性能问题,需要开发者仔细管理依赖数组和记忆化策略。
  4. 无法完全模拟React生命周期
    • getSnapshotBeforeUpdate
    • getDerivedStateFromError
    • componentDidCatch

demo

说了那么多,我们用一个例子理解Hook

import { useState, useEffect, useCallback, useMemo } from 'react';

const Counter: React.FC = () => {
  const [count, setCount] = useState(0);

  const addCount = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  const text = useMemo(() => {
    return `You clicked ${count} times`;
  }, [count]);

  useEffect(() => {
    document.title = text;
    return () => {
      document.title = 'React App';
    };
  }, [text]); // 仅在 text 变化时重新运行副作用

  return (
    <div>
      <p>{text}</p>
      <button onClick={addCount}>Click me to add</button>
    </div>
  );
};

export default Counter;

在这个打点计数器里

  • useState管理状态:初始化 count 值为0,以及更新函数setCount
  • useEffect触发副作用:
    • 使用 useEffect 动态更新 document.titletext
    • 清理函数在组件卸载时和下次 useEffect 运行之前执行,恢复 document.titleReact App
  • useCallback优化函数:优化addCount函数缓存,防止多个状态影响组件重新渲染时都重新生成新的函数,(当然这个例子无用)
  • useMemo 优化计算:使用 useMemo 记住 text 的计算结果,只有在 count 变化时才重新计算。避免重复计算导致性能问题

以此大家应该对函数式组件和常用的React Hook 有了一些认识

以上我们把React中的一些主要的思想和特性交流了一番,其实React的技术核心不止于此,像中间提到的调和算法(fiber)也很值得深入学习,但是本次是以介绍为主,时间有限我们之后在聊

React 学习路径

  1. 官⽹react.dev/ :新官⽹以实践为主,一步步教你书写 React 组件代码,教你新特性,是最好的 React 教材

  2. b站或者油管上各种免费讲解课程

  3. 购买对应付费课程

Code才是最好的学习⽅式,只看不敲代码,很难真的掌握语⾔,如有余⼒可以深⼊研究源码,甚⾄写一个 mini-react,更了解本质

React In Web3

React在Web3行业同样也有很广泛的应用,在交易所、Dapp、钱包中,都可以使用React配合Wagmi、viem来实现链交互、页面搭建等应用,而且海外React岗位远高于其他前端框架,学好React收益很大

转载自:https://juejin.cn/post/7371779128477925415
评论
请登录