React 是 Facebook 在2013年开源的用于构建用户界面的 JavaScript 库。React 不是一个框架 —— 它的应用甚至不局限于 Web 开发,它可以与其他库一起使用以渲染到特定环境。例如,React Native 可用于构建移动应用程序;React 360 可用于构建虚拟现实应用程序……
为了构建 Web 应用,开发人员将 React 与 ReactDOM 结合使用。React 和 ReactDOM 通常被与其他真正的 Web 开发框架相提并论,并用于解决相同的问题。当我们将 React 称为“框架”时,就是在进行口语化的理解。React的特点包括:
- 声明式(即以结果为导向的)
- 组件化
- 跨平台编写
一、三个重要的API
首先,我们通过引入外部JS脚本的方式来简单体会一下使用React开发Web项目,以下是一个简单的HelloWord程序。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello Word</title>
<!-- 引入React核心库 -->
<script src="./script/react.development.js"></script>
<!-- 引入React的DOM库 -->
<script src="./script/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
<script>
// 创建一个React元素
const div = React.createElement('div', {
id: 'content',
className: 'hello',
onClick: () => {
alert('hello word!')
}
}, 'Hello Word!')
// 获取根元素
const root = ReactDOM.createRoot(document.getElementById('root'));
// 将元素在根元素中显示
root.render(div)
// ******************************
//原生方法
// 通过DOM向页面中添加一个div
// 创建一个div
// const div = document.createElement('div'); // 创建一个dom元素
// // 向div中设置内容
// div.innerText = '我是一个div';
// // 获取root
// const root = document.getElementById('root');
// // 将div添加到页面中
// root.appendChild(div);
</script>
</body>
</html>
在上述代码中,有三个非常重要的API:
- React.createElement(type, [props], [...children]) 用来创建React元素, 注意React元素创建后是无法修改的,而是通过生成新的React元素去替换原来的React元素来达到修改的目的。
- ReactDOM.createRoot.createRoot(container[, options]) 用来创建React的根容器,容器用来放置 React 元素。
- root.render(element) 当首次调用时,容器节点里的所有DOM元素都会被替换,后续的调用则会使用React的DOM差分算法(DOM Diff Algorithm)进行高效的更新。
二、一些基础概念
1.JSX
JSX 是 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以它既具备了 Javascript 的灵活性,同时又兼具 html 的语义化和直观性。在 React 中,JSX 可以生成 React “元素”。JSX更像一种模板,类似于Vue中的 template。以下为一段基于JSX实现渲染列表的代码,是不是很方便?我们不再需要写很多很多的React.createElement()了~
//渲染列表
let data = ['孙悟空', '猪八戒', '唐僧']
let ul = <ul>{data.map(item => <li key={item}>{item}</li>)}</ul>
let root = ReactDOM.createRoot(document.getElementById('root'))
root.render(ul)
事实上,JSX就是一种语法糖,在内部 Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用,创建对应的 DOM 对象,转换后的代码如下所示:
var data = ['孙悟空', '猪八戒', '唐僧'];
var ul = /*#__PURE__*/React.createElement("ul", null, data.map(function (item) {
return /*#__PURE__*/React.createElement("li", {
key: item
}, item);
}));
var root = ReactDOM.createRoot(document.getElementById('root'));
root.render(ul);
一些关于JSX的注意事项:
- JSX不是字符串,不要加引号
- JSX中html标签应该小写,React组件应该大写开头
- JSX的标签必须正确结束(自结束标签必须写/)
- 在JSX中可以使用{}嵌入表达式,如果表达式是空值、布尔值、undefined,将不会显示
- 在JSX中,属性可以直接在标签中设置,class需要使用className代替,style中必须使用对象设置,如:style={{background:'red'}}
2.虚拟DOM
在React我们操作的元素被称为React元素,并不是真正的原生DOM元素,React通过虚拟DOM 将React元素 和 原生DOM,进行映射,虽然操作的React元素,但是这些操作最终都会在真实DOM中体现出来。那么什么是虚拟DOM呢?虚拟DOM可以看做一棵模拟了DOM树的JavaScript对象树。比如:
var element = {
element: 'ul',
props: {
id:"list"
},
children: [
{ element: 'li', props: { id:"first" }, children: ['这是第一个List元素'] },
{ element: 'li', props: { id:"second" }, children: ['这是第二个List元素'] }
]
}
虚拟DOM存在的意义在于:
- 降低API复杂度,即以原生的方式操作DOM, API多且复杂在实际开发中多有不便
- 解决兼容问题,即以原生的方式操作DOM, 需要考虑不同浏览器不同版本间的兼容性问题
- 提升性能,即通过Diff算法对比新旧虚拟DOM, 能减少DOM的不必要操作
3.组件
组件是应用程序根据UI结构划分的不同功能的代码的集合,其主要特点可概括为:独立、可复用、可组合。 React组件有两种创建方式,即 Class组件 和 函数式组件。
使用 ES6 的 class 创建的组件,叫做类(Class)组件, 示例如下:
const title = <h1>Class组件</h1>
// 1. 定义一个类组件
class MyDiv extends React.Component {
render () {
return <div>这是一个div</div>
}
}
// 2.使用组件,单标签和双标签模式使用都可以
const content = (
<div>
{title}
{<MyDiv />}
</div>
)
// 渲染
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content)
Class组件定义的注意事项:
- 类名必须以大写字母开头
- extends是一个关键字,用来实现类之间的继承。类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性。
- 类组件必须提供 render 方法,render 方法必须有返回值,表示该组件的 UI 结构。render会在组件创建时执行一次
使用 JS 的函数(或箭头函数)创建的组件,叫做函数式组件, 示例如下:
const title = <h1>react中的函数式组件</h1>
// 1.使用箭头函数定义一个函数式组件
const MyDiv = () => {
return <div>给我一个div</div>
}
// 2.使用普通函数定义一个函数式组件
function Button() {
return <button></button>
}
// 3.使用组件,单标签和双标签模式使用都可以
const content = (
<div>
{title}
{<MyDiv />}
{<Button />}
</div>
)
// 渲染
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(content)
函数式的注意事项:
- 函数名首字符大写,组件名称须以大写字母开头,React 据此区分 组件 和 普通的 HTML
- 必须有返回值,表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null