文章目录
1. React介绍和特点
1.1 React是什么
- React:用于构建用户界面的 JavaScript 库;
- React的官网文档:https://zh-hans.reactjs.org/
1.2 React的特点
1、声明式编程
- 声明式编程是目前整个大前端开发的模式:Vue、React、Flutter、SwiftUI;
- 它允许我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染我们的UI界面;
2、组件化开发
- 组件化开发页面是目前前端的流行趋势,我们会将复杂的界面拆分成一个个小的组件;
- 如何合理的进行组件的划分和设计也是后面学习的一个重点;
3、多平台适配
- 2013年,React发布之初主要是开发Web页面;
- 2015年,Facebook推出了ReactNative,用于开发移动端跨平台;(虽然目前Flutter非常火爆,但是还是有很多公司在使用 ReactNative);
- 2017年,Facebook推出ReactVR,用于开发虚拟现实Web应用程序;
2. React的开发依赖
2.1 React的三个依赖
开发React必须依赖三个库:
react
:包含react所必须的核心代码react-dom
:react渲染在不同平台所需要的核心代码babel
:将jsx转换成React代码的工具
对于Vue来说,我们只是依赖一个vue.js文件即可,但是react要依赖三个包;这三个库是各司其职的,目的就是让每一个库只单纯做自己的事情;
为什么要进行拆分呢?原因就是react-native。
- react包中包含了 react web 和 react-native 所共同拥有的核心代码。
- react-dom针对web和native所完成的事情不同:
- web端:react-dom会将jsx最终渲染成真实的DOM,显示在浏览器中
- native端:react-dom会将jsx最终渲染成原生的控件(比如Android中的Button,iOS中的UIButton)。
2.2 Babel和React的关系
babel是什么呢?
- Babel ,又名 Babel.js;是目前前端使用非常广泛的编译器、转移器。
- 比如当下很多浏览器并不支持ES6的语法,但开发者希望使用ES6的简洁、强大的语法去开发项目。
- 那么编写源码时我们就可以使用ES6来编写,之后通过Babel工具,将ES6转成大多数浏览器都支持的ES5的语法。
React和Babel的关系:
- 默认情况下开发React其实可以不使用babel。
- 但是前提是我们自己使用
React.createElement
来编写源代码,但它编写的代码非常的繁琐,可读性差。 - 那么我们就可以直接编写
jsx(JavaScript XML)
的语法,并且让babel帮助我们转换成 React.createElement 。
2.3 React的依赖引入
在编写React代码时,上述三个依赖都是必不可少的;引入方式:
- 方式一:直接CDN引入
- 方式二:下载后,添加本地依赖
- 方式三:通过npm管理(后续脚手架再使用)
<!-- 在编写react的代码前引入-->
<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>
这里的 crossorigin
的属性,目的是为了拿到跨域脚本的错误信息
3. React 入门案例
3.1 入门案例
快速体验React
【案例一】需求:在界面上通过 React 显示一个 hello world(关注非注释代码即可)
<!-- 以下为html文件,省略了非关键代码-->
<body>
<div id="root"></div>
<!-- 添加依赖 三个包 采用CDN引入 -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
// 编写React代码(jsx语法)
// jsx 语法 -> 普通的javascript代码 -> babel
// 渲染 hello world
// React18之前用:ReactDOM.render
// ReactDOM.render(<h2>hello world</h2>, document.querySelector("#root"));
// react18之后:
const message = "hello world"
const root = ReactDOM.createRoot(document.querySelector("#root")); // 创建根元素
root.render(<h2>{
message}</h2>); // 在根元素上渲染内容
// 可以如下创建多个根 ,但一般是一个
// const app = ReactDOM.createRoot(document.querySelector("#app"));
// app.render(<h2>hello react</h2>);
</script>
</body>
- 注意:这里我们编写 React 的
script
代码中,必须添加type="text/babel"
,作用是可以让babel解析jsx的语法
必要说明:
ReactDOM.createRoot
函数:用于创建一个 React 根,之后渲染的内容会包含在这个根中- 参数:将渲染的内容,挂载到哪一个HTML元素上(如上已经提定义一个 id 为app 的 div)
root.render
函数:- 参数:要渲染的根组件
- 可以通过
{}
语法来引入外部的变量或者表达式
【案例二】:需求:封装 render 函数,点击按钮改变文本 (为了简洁后续代码省略引入的依赖)
<script type="text/babel">
const root = ReactDOM.createRoot(document.querySelector("#root"));
// 1. 将文本定义为变量
let message = "hello world";
// 2. 监听按钮的点击
function btnClick() {
// 2.1 修改数据
message = "hello react";
// 2.2 重新渲染界面
rootRender();
}
// 3. 封装一个渲染函数
function rootRender() {
root.render(
<div>
<h2>{
message}</h2>
<button onClick={
btnClick}>点击修改文本</button>
</div>
);
}
// 先调用一次
rootRender();
</script>
3.2 组件化开发
3.2.1 封装组件
上面的案例整个逻辑其实可以看做一个整体,那么我们就可以将其封装成一个组件:
- 基于
root.render
参数是一个HTML元素或者一个组件; - 所以可以先将之前的业务逻辑封装到一个组件中,然后传入到
ReactDOM.render
函数中的第一个参数;
在React中,这里暂时使用类的方式封装组件,步骤:
- 1.定义一个类 继承自
React.Component
(类名大写,组件的名称是必须大写的,小写会被认为是HTML元素) - 2.实现当前组件的
render
函数 (render当中返回的 jsx 内容,就是之后 React 会帮助我们渲染的内容)
// 定义App根组件
class App extends React.Component {
render() {
return <h2>hello world</h2>;
}
}
// 创建root并渲染 App根组件
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(<App />);
3.2.2 数据依赖
组件化问题一:数据在哪里定义?
在组件中的数据可以分成两类:
- 参与界面更新的数据:当数据变时,需要更新组件渲染的内容;
- 不参与界面更新的数据:当数据变时,不需要更新将组建渲染的内容;
参与界面更新的数据我们也可以称之为是参与数据流,这个数据是定义在当前对象的state
中
- 可以通过在构造函数中
this.state = {定义的数据}
- 当数据发生变化时,我们可以调用
this.setState
来更新数据,并且通知React进行update操作; - 在进行update操作时,就会重新调用render函数,并且使用最新的数据,来渲染界面
// 定义App根组件
class App extends React.Component {
constructor() {
super();
this.state = {
message: "hello world",
};
}
render() {
const {
message } = this.state;
return <h2>{
message}</h2>;
}
}
3.2.3 事件绑定
组件化问题二:事件绑定中的this
在类中直接定义一个函数,并且将这个函数绑定到元素的onClick
事件上,当前这个函数的this指向的是谁呢?
默认情况下竟是 undefined,解释:
- 在正常的DOM操作中,监听点击,监听函数中的this其实是节点对象(比如说是button对象);
- 这次因为 React 并不是直接渲染成真实的DOM,我们所编写的 button 只是一个语法糖,它的本质React的Element对象;
- 那么在这里发生监听的时候,react在执行函数时并没有绑定this,默认情况下就是一个undefined;
我们在绑定的函数中,可能想要使用当前对象,比如执行 this.setState
函数,就必须拿到当前对象的 this
- 我们需要在传入函数时,手动给这个函数直接绑定this
- 类似于下面的写法:
<button onClick={this.changeText.bind(this)}>改变文本</button>
// 使用组件进行重构
// 类组件 / 函数式组件(下面为类组件)
// 类App 必须继承 React.Component 才能成为组件
class App extends React.Component {
// 组件数据
constructor() {
super();
this.state = {
message: "hello world",
};
// 对需要绑定的方法,提前绑定好 this
// 若这里绑定了,在下面render中的button中就不需要绑定了
//this.btnClick = this.btnClick.bind(this);
}
// 组件方法(实例方法)
btnClick() {
console.log("btn", this);
// react内部做了监视:1.将 state中message的值修改掉 2. 自动执行render函数
this.setState({
message: "hello react",
});
}
// 渲染内容 必须 实现render方法
render() {
return (
<div>
<h2>{
this.state.message}</h2>
<button onClick={
this.btnClick.bind(this)}>修改文本</button>
</div>
);
}
}
3.4 案例练习
【案例一:电影列表展示】(关注列表渲染形式)
<body>
<!-- 结构根元素 -->
<div id="root"></div>
<!-- 这里在本地引入react三个依赖-->
<script src="../lib/react.js"></script>
<script src="../lib/react-dom.js"></script>
<script src="../lib/babel.js"></script>
<script type