重学 React 之基础认知

863 阅读6分钟

前言

其实我两年前就学过 React,我在掘金上的第一篇文章就是写 Redux 的,但是工作中一直未使用到,算一个小遗憾吧,哈哈。

我工作中一直使用的 Vue,也是从 Vue1 用到现在的 Vue3,前阵子有时间有想法学 React,就又重学了一遍 React,是通过看视频,看博客,看文档的方式。一边学一边记录,本来笔记都是存到 github 上的,最近想想要不也发掘金上来吧,这样有点错误还能收获批评不是😄(其实根本没人评论)。

我把之前写的笔记再重新组织润色了下,原先只想写成一篇文章发出来,但想着分开看更清晰点,就拆成多篇。这是第一篇介绍 React 的一些基础概念,包括怎么使用 React,JSX介绍以及组件介绍等等。先声明它不是纯零基础的记录,但也写不出晦涩难懂的话。如果你是 Vue 使用者,并且想学 React,相信会有所收获。

本文 React 用例版本:v17.0.2

怎么使用 React

这里说的 React 使用,是指怎么引用 React,不是指 React 语法。

在实际开发中,React 基本都是集成在脚手架中使用的,我们不需要特别关注怎么安装引用。那么脱离脚手架后该怎么引用 React 呢?其实这里是想说明 React 不同于 Vue,使用 Vue 时引入一个 vue.js 就行了,但 React 不行,它要引用的不止一个文件。

这是一个 html 文件中使用 React 的例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React Demo</title>
</head>
<body>
    <!-- react 应用的容器 -->
    <div id="test"></div> 

    <!-- 引入 react 核心库 -->
    <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
  
    <!-- 引入 react-dom,支持 React 操作 DOM -->
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>

    <script>
       // 使用 React.createElement 创建虚拟 DOM
       const VDOM = React.createElement('div',{},'hello,world!')
       // 将虚拟 DOM 渲染到容器里
       ReactDOM.render(VDOM,document.getElementById('test'))
    </script>
</body>
</html>

上述代码演示了使用 React 开发的一个基本过程:

  1. 首先 React 应用需要挂载到页面的一个容器上,所以我们需要定义一个最外层的容器,即代码中的 <div id="test"></div>
  2. 开发 React 应用需要用到两个基本库,即 react.jsreact-dom.js ,前者是核心库,暴露全局变量 React,后者是提供 DOM 操作相关功能,暴露全局变量 ReactDOM
  3. 使用 React 构建页面,其实就是在写虚拟 DOM,可以使用提供的 React.createElement 方法来创建虚拟 DOM,然后调用 ReactDOM.render方法来将虚拟 DOM 渲染成真实 DOM,挂载到容器上。这样就能在浏览器上看到所编写内容。

现在我们知道使用 React 需要用到最基本的两个库文件,即 react.jsreact-dom.js

但是有一处代码让人不适,就是 const VDOM = React.createElement('div',{},'hello,world!') ,它的意思是创建一个 div 元素,元素内容是 hello,world

很显然如果业务开发中使用这种写法来组织页面内容的话,估计也没有现在的 React 了。我们需要一种更优雅的方式来编写代码,聪明的童鞋一定猜到了,我要说的是 JSX。JSX 是 JavaScript 的语法扩展,它很像 HTML,但又不是 HTML,也不是字符串,更多的介绍我推荐直接看文档:JSX 简介

如果使用 JSX 的方式改写上面那串代码,会是这样:const VDOM = <div>hello,world</div>,是不是就跟写 html 一样,但千万要记住它不是 html 哦。但是但是!我们不能直接在 html 文件中使用 JSX,因为它不是 html 所以浏览器不认识它,需要将 JSX 代码进行一个转换。转换 JSX 需要使用 babel 插件,所以上面的 html 文件,我们要多引入一个 babel 插件,同时代码改写为 JSX 方式,完整代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React JSX Demo</title>
</head>
<body>
    <!-- react 应用的容器 -->
    <div id="test"></div> 

    <!-- 引入 react 核心库 -->
    <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
  
    <!-- 引入 react-dom,支持 React 操作 DOM -->
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>

    <!-- 引入 babel,用来转转译 JSX 语法 -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <!-- 注意:这里的 type 要写成 text/babel -->
    <script type="text/babel">
       // 编写 JSX 代码
       const VDOM = <div>hello,world!</div>
       // 将虚拟 DOM 渲染到容器里
       ReactDOM.render(VDOM,document.getElementById('test'))
    </script>
</body>
</html>

需要注意的就是包裹 JSX 代码的 script 标签,需要加上 type="text/babel"

以上我们学习了正常使用 React 时需要引入三个文件,即 react.jsreact-dom.jsbabel.js

JSX 特性

JSX 写起来很像在写 html,但这两个完全不是一个东西。JSX 其实算是 JS 的一种扩展语法,最终会转换成一个虚拟 DOM 的对象。下面介绍一下使用 JSX 的注意事项。

不要用引号

最容易犯的错误就是用引号来包裹 JSX 语句,就像这样:

const dom = "<p>hello world</p>"

这样写的话其实还是受 js 的写法影响,JSX 并不是字符串,如果写成字符串的话,React 就不能生成虚拟 DOM 了,从而不能渲染成最终的 html 标签。

需要一个根元素

<div>
  <p>aaaaaa</p>
  <p>bbbbbb</p>
  <div>
    <p>hello</p>
  </div>
</div>

如上,在最外层需要包裹一个根元素,这跟 vue 中的 template是一样的。不过 vue3 已经支持多个根元素了。

表达式要用 { } 包裹

JSX 中插入变量时,需要用 {} 包裹,注意 {} 中需要使用 js 表达式,不是所有的 js 语句都能生效的。区分是不是表达式的方法就是是否可以赋值给一个变量。比如渲染一个列表,可以这样:

const arr = ['Vue','React','Angular']
const VDOM = (
  <ul>
    {arr.map(item=><li>{item}</li>)}
  </ul>
)
ReactDOM.render(VDOM,document.getElementById('test'))

可以使用 map,但不能使用 forforEach 等循环语句,因为不是 js 表达式。

标签类名要用 className

JSX 里要写类名时,不能用 class,而是要用 className

<h1 className="title"></h1>

// 这样时错误的
<h1 class="title"></h1>

始终记住,JSX 并不是等同 html,因为 class 是 js 中的关键字,为了避免冲突,类名定义需要使用 className

内联 style 需要使用双大括号包裹

内联样式使用如下:

<p style={{color:'red'}}></p>

外层 {} 就是上面说到的表达式需要使用这个符号包裹,而内部的 {} 其实就是对象,这个对象是采用小驼峰命名属性的,像是 font-size 这样的样式,需要这样写:

<p style={{fontSize:'15px'}}></p>

标签必须闭合

JSX 中的标签必须严格闭合,尤其是一些自闭和标签也不要忘记闭合,如:

<img src="" />
<input />

自定义标签

除了浏览器能识别的 html 标签,有时我们也会写出一些自定义标签。JSX 在处理这些标签时,会根据标签的首字母大小写来进行不同操作:

  1. 若标签首字母是小写的,JSX 会将该标签转化为 html 中的同名标签,若 html 中不存在该同名标签,会正常显示内容,但会提示不规范;
  2. 若标签首字母是大写的,React 会将它当作一个组件渲染,若没有此组件,就会报错。

认识 React 中的组件

React 中的组件有两种编写形式,即 函数组件类组件

函数组件

函数组件即定义一个函数,返回 JSX 内容,如下:

<script type="text/babel">
  function MyComponent(){
    return <h1>hello world</h1>
  }
  ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>

需要注意的是,函数名首字母需要大写。使用时无需主动调用函数,函数名标签使用后,React 会自动调用函数。

另外函数内部的 this 指向 undefined,因为函数内部启用了严格模式。

类组件

<script type="text/babel">
  class MyComponent extends React.Component{
    render(){
      return (
        <h1>hello,world</h1>
      )
    }
  }
  ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>

使用 class 定义类组件,需要继承 React.Component 内置类,同时类内部必须定义 render 方法,用于返回 JSX 内容。

constructor 并不是必须要的,但是如果写了 constructor ,则必须调用 super 方法,表示继承,如下:

class MyComponent extends React.Component{
  constructor(){
    super() // 这里必须调用 super 方法,且需要在所有用到 this 的代码之前调用
    console.log(this); // MyComponent {}
  }
  render(){
    return (
      <h1>hello,world</h1>
    )
  }
}

this 指向这个类的实例,虽然没有主动 new ,但是 React 内部自动给这个类实例化了。

结尾

如有错误,欢迎指出。