Skip to content
On this page

React 是什么

React 是一个用于构建用户界面的 JavaScript 库 核心专注于视图,目的实现组件化开发

构建页面三要素

  • HTML:构建页面的结构
  • CSS:构建页面的样式
  • JavaScript:页面动态内容和交互

那么使用最原生的 HTML、CSS、JavaScript 可以构建完整的用户界面吗?当然可以,但是会存在很多问题?

  • 比如操作 DOM 兼容性的问题;
  • 比如过多兼容性代码的冗余问题;
  • 比如代码组织和规范的问题;

React 的起源

React 是 2013 年,Facebook 开源的 JavaScript 框架,那么当时为什么 Facebook 要推出这样一款框架呢?

这个源于一个需求,所产生的 bug:

  • 该功能上线之后,总是出现 bug;
  • 三个消息的数字在发生变化时,过多的操作很容易产生 bug;

bug 是否可以修复呢?当然可以修复,但是 Facebook 的工程师并不满足于此;

  • 他们开始思考为什么会产生这样的问题;
  • 在传统的开发模式中,我们过多的去操作界面的细节;(前端、iOS、Android) √并且需要掌握和使用大量 DOM 的 API,当然我们可以通过 jQuery 来简化和适配一些 API 的使用;
  • 另外关于数据(状态),往往会分散到各个地方,不方便管理和维护;

他们就去思考,是否有一种新的模式来解决上面的问题:

  1. 以组件的方式去划分一个个功能模块
  2. 组件内以 jsx 来描述 UI 的样子,以 state 来存储组件内的状态
  3. 当应用的状态发生改变时,通过 setState 来修改状态,状态发生变化时,UI 会自动发生更新

React 是 Web 前端框架

目前市面上比较主流的前端框架

  • React
  • Vue
  • Angular「NG」
  • ...

主流的思想:不在直接去操作 DOM,而是改为“数据驱动思想”

操作 DOM 思想:

  • 操作 DOM 比较消耗性能「主要原因就是:可能会导致 DOM 重排(回流)/ 重绘」
  • 操作起来也相对来讲麻烦一些
  • ...

数据驱动思想:

  • 我们不会在直接操作 DOM
  • 我们去操作数据「当我们修改了数据,框架会按照相关的数据,让页面重新渲染」
  • 框架底层实现视图的渲染,也是基于操作 DOM 完成的
    • 构建了一套 虚拟 DOM->真实 DOM 的渲染体系
    • 有效避免了 DOM 的重排 / 重绘
  • 开发效率更高、最后的性能也相对较好

React 的特点

声明式编程

  • 声明式编程是目前整个大前端开发的模式:Vue、React、Flutter、SwiftUI
  • 它允许我们只需要维护自己的状态,当状态改变时,React 可以根据最新的状态去渲染我们的 UI 界面

组件化开发

  • 页面目前前端的流行趋势,我们会讲复杂的界面拆分成一个个小的组件;
  • 如何合理的进行组件的划分和设计也是后面我会讲到的一个重点;

组件化的概念

  • 可组合:一个组件可以和其他的组件一起使用或者可以直接嵌套在另一个组件内部
  • 可重用:每个组件都是具有独立功能的,它可以被使用在多个场景中
  • 可维护:每个小的组件仅仅包含自身的逻辑,更容易被理解和维护

React 开发依赖

开发 React 必须依赖三个库:

  • react:包含 react 所必须的核心代码
  • react-dom:react 渲染在不同平台所需要的核心代码
  • babel:将 jsx 转换成 React 代码的工具

为什么 React 要依赖三个库?

  • 目的就是让每一个库只单纯做自己的事情
  • 在 React 的 0.14 版本之前是没有 react-dom 这个概念的,所有功能都包含在 react 里

为什么要进行拆分呢?

  • 原因就是 react-native
  • react 包中包含了 react 和 react-native 所共同拥有的核心代码

react-dom 针对 web 和 native 所完成的事情不同?

  • web 端:react-dom 会讲 jsx 最终渲染成真实的 DOM,显示在浏览器中
  • native 端:react-dom 会讲 jsx 最终渲染成原生的控件(比如 Android 中的 Button,iOS 中的 UIButton)

引入 React 依赖

  • 方式一:直接 CDN 引入
  • 方式二:下载后,添加本地依赖
  • 方式三:通过 npm 管理(后续脚手架再使用)
javascript
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
 <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
1
2
3

Hello World => Hello React

html
<body>
    <div id="app"></div>
    <script type="text/babel">
        // 讲数据定义在变量中
        let message = "Hello Word";

        // 定义 Dom
        const root = ReactDOM.createRoot(document.getElementById("app"));

        function btnClick() {
            message = "Hello React";
            render();
        }

        render()

        function render() {
            root.render(
                <div>
                    <h2>{message}</h2>
                    <button onClick={btnClick}>改变文本</button>
                </div>
            );
        }

    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

状态

  • 组件的数据来源有两个地方,分别是属性对象和状态对象
  • 属性是父组件传递过来的(默认属性,属性校验)
  • 状态是自己内部的,改变状态唯一的方式就是 setState
  • 属性和状态的变化都会影响视图更新
javascript
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
    constructor(props) {
      super(props);
      this.state = {date: new Date()};
    }
    componentDidMount() {
      this.timerID = setInterval(
        () => this.tick(),
        1000
      );
    }
    componentWillUnmount() {
      clearInterval(this.timerID);
    }
    tick() {
      this.setState({
        date: new Date()
      });
    }
    render() {
      return (
        <div>
          <h1>Hello, world!</h1>
          <h2>It is {this.state.date.toLocaleTimeString()}</h2>
        </div>
      );
    }
  }
  ReactDOM.render(
    <Clock />,
    document.getElementById('root')
  );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
沪ICP备20006251号-1