前言
其实我两年前就学过 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 开发的一个基本过程:
- 首先 React 应用需要挂载到页面的一个容器上,所以我们需要定义一个最外层的容器,即代码中的
<div id="test"></div>; - 开发 React 应用需要用到两个基本库,即
react.js和react-dom.js,前者是核心库,暴露全局变量React,后者是提供 DOM 操作相关功能,暴露全局变量ReactDOM; - 使用 React 构建页面,其实就是在写虚拟 DOM,可以使用提供的
React.createElement方法来创建虚拟 DOM,然后调用ReactDOM.render方法来将虚拟 DOM 渲染成真实 DOM,挂载到容器上。这样就能在浏览器上看到所编写内容。
现在我们知道使用 React 需要用到最基本的两个库文件,即 react.js 和 react-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.js、react-dom.js 和 babel.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,但不能使用 for 、forEach 等循环语句,因为不是 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 在处理这些标签时,会根据标签的首字母大小写来进行不同操作:
- 若标签首字母是小写的,JSX 会将该标签转化为 html 中的同名标签,若 html 中不存在该同名标签,会正常显示内容,但会提示不规范;
- 若标签首字母是大写的,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 内部自动给这个类实例化了。
结尾
如有错误,欢迎指出。