React系列(一) -邂逅React开发

简介: 我个人一直喜欢使用邂逅这个词,我希望每个人在和一个新技术接触的时候,都是一场美丽的邂逅。而React本身绝对是优雅和美丽的,所以从这里开始,我们和React来一场美丽的邂逅吧!

一. 认识React


1.1. React是什么?


React是什么呢?相信每个做前端的人对它都或多或少有一些印象。

这里我们来看一下官方对它的解释:用于构建用户界面的 JavaScript 库。

image.png                                                   React是什么?

我们知道对于前端来说,主要的任务就是构建用于界面,而构建用于界面离不开三个技术:

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

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

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

所以,一直以来前端开发人员都在需求可以让自己开发更方便的JavaScript库:

  • 在过去的很长时间内,jQuery是被使用最多的JavaScript库;
  • 在过去的一份调查中显示,全球前10,000个访问最高的网站中,有65%使用了jQuery,是当时最受欢迎的JavaScript库;
  • 但是越来越多的公司开始慢慢不再使用jQuery,包括程序员使用最多的GitHub;

现在前端领域最为流行的是三大框架:

  • Vue
  • React
  • Angular

image.png                  

                                                 三个框架

而Angular在国内并不是特别受欢迎,尤其是Angular目前的版本对TypeScript还有要求的情况下。

Vue和React是国内最为流行的两个框架,而他们都是帮助我们来构建用户界面的JavaScript库。

  • 关于它们的对比,我会另外再写一篇文章


1.2. React的起源


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

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

image.png

                              Facebook功能需求

该功能上线之后,总是出现bug:

  • 三个消息的数字在发生变化时,过多的操作很容易产生bug;

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

他们开始思考为什么会产生这样的问题;

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

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

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


1.3. React的特点和优势


1.3.1. React的特点


声明式编程:

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

image.png                                                        声明式编程

组件化开发:

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

image.png                                                    组件化开发

多平台适配:

  • 2013年,React发布之初主要是开发Web页面;
  • 2015年,Facebook推出了ReactNative,用于开发移动端跨平台;(虽然目前Flutter非常火爆,但是还是有很多公司在使用ReactNative);
  • 2017年,Facebook推出ReactVR,用于开发虚拟现实Web应用程序;(随着5G的普及,VR也会是一个火爆的应用场景);

image.png                                

                                       react多平台


1.3.2. React的优势


React由Facebook来更新和维护,它是大量优秀程序员的思想结晶:

  • React的流行不仅仅局限于普通开发工程师对它的认可,大量流行的其他框架借鉴React的思想;

Vue.js框架设计之初,有很多的灵感来自Angular和React。

  • 包括Vue3很多新的特性,也是借鉴和学习了React
  • 比如React Hooks是开创性的新功能(也是我们课程的重点)
  • Vue Function Based API学习了React Hooks的思想

Flutter的很多灵感都来自React,来自官网的一段话:(SwiftUI呢)

image.png                                                 来自Flutter官网

  • 事实上Flutter中的Widget – Element – RenderObject,对应的就是JSX – 虚拟DOM – 真实DOM

所以React可以说是前端的先驱者,它总是会引领整个前端的潮流。


1.4. React的现状


另外在HackerRank中,2020年有一份调用,你更想要学习的framework(框架):

image.png                                       哪一个是你最想要学习的框架

国内外很多知名网站使用React开发:

image.png

目前国内在大型公司使用React的较多:

image.png                                               高级前端工程师要求


二. Hello React


2.1. 原生案例实现


为了演练React,我们可以提出一个小的需求:

  • 在界面显示一个文本:Hello World
  • 点击下方的一个按钮,点击后文本改变为Hello React
  • 在界面显示一个文本:Hello World
  • 点击下方的一个按钮,点击后文本改变为Hello React

image.png                                                         案例效果

但是,我们使用React实现之前,先使用原生代码来实现,这样更加方便大家对比React和原生:

  • 当然,你也可以使用jQuery和Vue来实现,对它们分别进行对比学习

原生实现代码如下:

<body>
  <div class="app">
    <h2 class="title">Hello World</h2>
    <button class="change-btn">改变文本</button>
  </div>
  <script>
    // 1.获取dom节点
    const titleEl = document.getElementsByClassName("title")[0];
    // 2.获取数据
    let message = "Hello World";
    // 3.将数据显示到titleEl中
    titleEl.innerHTML = message;
    // 4.改变按钮内容
    const btnEl = document.getElementsByClassName("change-btn")[0];
    btnEl.addEventListener('click', (e) => {
      message = "Hello React";
      titleEl.innerHTML = message;
    })
  </script>
</body>


2.2. React开发依赖


开发React必须依赖三个库:

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

第一次接触React会被它繁琐的依赖搞蒙,对于Vue来说,我们只是依赖一个vue.js文件即可,但是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)。

babel是什么呢?

  • Babel ,又名 Babel.js
  • 是目前前端使用非常广泛的编辑器、转移器。
  • 比如当下很多浏览器并不支持ES6的语法,但是确实ES6的语法非常的简洁和方便,我们开发时希望使用它。
  • 那么编写源码时我们就可以使用ES6来编写,之后通过Babel工具,将ES6转成大多数浏览器都支持的ES5的语法。

React和Babel的关系:

  • 默认情况下开发React其实可以不使用babel。
  • 但是前提是我们自己使用 React.createElement 来编写源代码,它编写的代码非常的繁琐和可读性差。
  • 那么我们就可以直接编写jsx(JavaScript XML)的语法,并且让babel帮助我们转换成React.createElement。
  • 后续还会讲到;

所以,我们在编写React代码时,这三个依赖都是必不可少的。

那么,如何添加这三个依赖:

  • 方式一:直接CDN引入
  • 方式二:下载后,添加本地依赖
  • 方式三:通过npm管理(后续脚手架再使用)

暂时我们直接通过CDN引入,来演练下面的示例程序:

  • 这里有一个crossorigin的属性,这个属性的目的是为了拿到跨域脚本的错误信息
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>


2.3. Hello World


下面我们通过一个Hello World的案例来看下如何使用React开发。

需求非常简单:通过React,在界面上显示一个Hello World

  • 注意:这里我们编写React的script代码中,必须添加 type="text/babel",作用是可以让babel解析jsx的语法
<div id="app"></div>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <script type="text/babel">
    // 通过ReactDom对象来渲染内容
    ReactDOM.render(<h2>Hello World</h2>, document.getElementById("app"));
  </script>

代码解析:

  • 依赖不需要多讲,开发React代码必须添加三个依赖;
  • ReactDOM.render函数:
  • 这里我们已经提前定义一个id为app的div
  • 这里我们传入了一个h2元素,后面我们就会使用React组件
  • 参数一:传递要渲染的内容,这个内容可以是HTML元素,也可以是React的组件
  • 参数二:将渲染的内容,挂载到哪一个HTML元素上

显示效果:

image.png        

      Hello World

但是目前我们渲染的内容是定义死的,能否将其抽取到一个变量中呢?

  • 当然可以,我们可以通过{}语法来引入外部的变量或者表达式
// 将数据定义到变量中
let message = "Hello World";
// 通过ReactDom对象来渲染内容
ReactDOM.render(<h2>{message}</h2>, document.getElementById("app"));


2.4. Hello React


按照我们最初的案例,我们已经实现了Hello World,但是我们希望点击一个按钮后,修改为Hello React


2.4.1. 错误的方式


下面的代码是我们正常的执行逻辑,但是会报错:

  • 原因是默认情况下 ReactDOM.render 会覆盖挂载到的app原生中的所有内容;
  • 所以在执行完 ReactDOM.render 之后,就不存在button原生了;
<body>
  <div id="app">
    <button class="change-btn">改变文本</button>
  </div>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <script type="text/babel">
    // 将数据定义到变量中
    let message = "Hello World";
    // 通过ReactDom对象来渲染内容
    ReactDOM.render(<h2>{message}</h2>, document.getElementById("app"));
    // 获取btn
    const btnEl = document.getElementsByClassName("change-btn")[0];
    btnEl.addEventListener("click", (e) => {
      console.log(e);
    })
  </script>
</body>


2.4.2. 正确的方式


虽然可以实现,但是整个代码的流畅过于繁琐

<body>
  <div id="app">
  </div>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <script type="text/babel">
    // 将数据定义到变量中
    let message = "Hello World";
    // 通过ReactDom对象来渲染内容
    render();
    // 定义一个执行的函数
    function btnClick() {
      message = "Hello React";
      render();
    }
    function render() {
      ReactDOM.render((
        <div>
          <h2>{message}</h2>
          <button onClick={btnClick}>改变文本</button>
        </div>
      ), document.getElementById("app"));
    }
  </script>
</body>


2.4.3. 组件的方式


整个逻辑其实可以看做一个整体,那么我们就可以将其封装成一个组件:

  • 我们说过 ReactDOM.render 第一参数是一个HTML原生或者一个组件;
  • 所以我们可以先将之前的业务逻辑封装到一个组件中,然后传入到 ReactDOM.render 函数中的第一个参数;

在React中,如何封装一个组件呢?

  • 这里我们暂时使用类的方式封装组件:
  • render当中返回的jsx内容,就是之后React会帮助我们渲染的内容
  • 1.定义一个类,继承自React.Component
  • 2.实现当前组件的render函数

具体的代码如下:

class App extends React.Component {
  render() {
    return (<h2>Hello World</h2>)
  }
}
ReactDOM.render(<App/>, document.getElementById("app"));

如果我们的Hello World是依赖变量的,并且会根据按钮的点击而改变呢?这里涉及到几个核心点

1.数据在哪里定义

  • 在组件中的数据,我们可以分成两类:
  • 参与界面更新的数据:当数据变量时,需要更新组件渲染的内容
  • 不参与界面更新的数据:当数据变量时,不需要更新将组建渲染的内容
  • 参与界面更新的数据我们也可以称之为是参与数据流,这个数据是定义在当前对象的state中
  • 我们可以通过在构造函数中 this.state = {定义的数据}
  • 当我们的数据发生变化时,我们可以调用 this.setState 来更新数据,并且通知React进行update操作
  • 在进行update操作时,就会重新调用render函数,并且使用最新的数据,来渲染界面

2.事件绑定中的this

  • 在类中直接定义一个函数,并且将这个函数绑定到html原生的onClick事件上,当前这个函数的this指向的是谁呢?
  • 默认情况下是undefined
  • 很奇怪,居然是undefined;
  • 因为在正常的DOM操作中,监听点击,监听函数中的this其实是节点对象(比如说是button对象);
  • 这次因为React并不是直接渲染成真实的DOM,我们所编写的button只是一个语法糖,它的本质React的Element对象;
  • 那么在这里发生监听的时候,react给我们的函数绑定的this,默认情况下就是一个undefined;
  • 我们在绑定的函数中,可能想要使用当前对象,比如执行 this.setState 函数,就必须拿到当前对象的this
  • 我们就需要在传入函数时,给这个函数直接绑定this
  • 类似于下面的写法:<button onClick={this.changeText.bind(this)}>改变文本</button>

我们一起来看一下代码是如何实现的:

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      message: "Hello World"
    };
  }
  render() {
    return (
      <div>
        <h2>{this.state.message}</h2>
        <button onClick={this.changeText.bind(this)}>改变文本</button>
     </div>
    )
  }
  changeText() {
    this.setState({
      message: "Hello React"
    })
  }
}
ReactDOM.render(<App/>, document.getElementById("app"));
相关文章
|
1月前
|
前端开发 JavaScript API
React开发需要了解的10个库
本文首发于微信公众号“前端徐徐”,介绍了React及其常用库。React是由Meta开发的JavaScript库,用于构建动态用户界面,广泛应用于Facebook、Instagram等知名网站。文章详细讲解了Axios、Formik、React Helmet、React-Redux、React Router DOM、Dotenv、ESLint、Storybook、Framer Motion和React Bootstrap等库的使用方法和应用场景,帮助开发者提升开发效率和代码质量。
114 4
React开发需要了解的10个库
|
3月前
|
设计模式 存储 前端开发
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
|
4月前
|
前端开发 JavaScript 安全
TypeScript在React Hooks中的应用:提升React开发的类型安全与可维护性
【7月更文挑战第17天】TypeScript在React Hooks中的应用极大地提升了React应用的类型安全性和可维护性。通过为状态、依赖项和自定义Hooks指定明确的类型,开发者可以编写更加健壮、易于理解和维护的代码。随着React和TypeScript的不断发展,结合两者的优势将成为构建现代Web应用的标准做法。
|
1月前
|
前端开发 JavaScript 开发者
React 组件化开发最佳实践
【10月更文挑战第4天】React 组件化开发最佳实践
48 4
|
2月前
|
XML 移动开发 前端开发
使用duxapp开发 React Native App 事半功倍
对于Taro的壳子,或者原生React Native,都会存在 `android` `ios`这两个文件夹,而在duxapp中,这些文件夹的内容是自动生成的,那么对于需要在这些文件夹中修改的配置内容,例如包名、版本号、新架构开关等,都通过配置文件的方式配置了,而不需要需修改具体的文件
|
2月前
|
资源调度 JavaScript 前端开发
使用vite+react+ts+Ant Design开发后台管理项目(二)
使用vite+react+ts+Ant Design开发后台管理项目(二)
|
3月前
|
JavaScript 前端开发 安全
[译] 使用 TypeScript 开发 React Hooks
[译] 使用 TypeScript 开发 React Hooks
|
3月前
|
移动开发 前端开发 JavaScript
"跨界大战!React Native、Weex、Flutter:三大混合开发王者正面交锋,揭秘谁才是你移动应用开发的终极利器?"
【8月更文挑战第12天】随着移动应用开发的需求日益增长,高效构建跨平台应用成为关键。React Native、Weex与Flutter作为主流混合开发框架各具特色。React Native依托Facebook的强大支持,以接近原生的性能和丰富的组件库著称;Weex由阿里巴巴开发,性能优越尤其在大数据处理上表现突出;Flutter则凭借Google的支持及独特的Dart语言和Skia渲染引擎,提供出色的定制能力和开发效率。选择时需考量项目特性、团队技能及生态系统的成熟度。希望本文对比能助你做出最佳决策。
158 1
|
3月前
|
前端开发
React——开发调式工具安装【五】
React——开发调式工具安装【五】
31 0
React——开发调式工具安装【五】
|
3月前
|
开发者 自然语言处理 存储
语言不再是壁垒:掌握 JSF 国际化技巧,轻松构建多语言支持的 Web 应用
【8月更文挑战第31天】JavaServer Faces (JSF) 框架提供了强大的国际化 (I18N) 和本地化 (L10N) 支持,使开发者能轻松添加多语言功能。本文通过具体案例展示如何在 JSF 应用中实现多语言支持,包括创建项目、配置语言资源文件 (`messages_xx.properties`)、设置 `web.xml`、编写 Managed Bean (`LanguageBean`) 处理语言选择,以及使用 Facelets 页面 (`index.xhtml`) 显示多语言消息。通过这些步骤,你将学会如何配置 JSF 环境、编写语言资源文件,并实现动态语言切换。
40 0