邂逅React
一、React的介绍和特点
1.1 React的介绍
-
React是什么?
-
React:用于构建用户界面的 JavaScript 库
-
-
1.2 React的特点
1.2.1 声明式编程
-
声明式编程是目前整个大前端开发的模式:Vue、React、Flutter、SwiftUI
-
我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染UI界面
1.2.2 组件化开发
- 组件化开发页面目前前端的流行趋势,每一个复杂的界面都能拆分成一个个小的组件
1.2.3 多平台适配
-
2013年,React发布之初主要是开发Web页面
-
2015年,Facebook推出了ReactNative,用于开发移动端跨平台
-
2017年,Facebook推出ReactVR,用于开发虚拟现实Web应用程序
二、React开发依赖分析
界面上显示一个按钮和一段文本,点击按钮切换文本
2.1 React 依赖三个包
-
react:包含react必须的核心代码
-
react-dom:react渲染在不同平台所需要的核心代码
- web端:react-dom会将jsx最终渲染成真实的DOM,显示在浏览器中
- native端:react-dom会将jsx最终渲染成原生的控件(比如Android中的Buttom,iOS中的UIButton)
-
babel:将jsx转换成React代码的工具
2.2 Babel 和 React 的关系
-
babel是什么?
-
是目前前端使用非常广泛的编译器、转移器。
-
比如当下很多浏览器并不支持ES6的语法,但是确实ES6的语法非常的简洁和方便,我们开发时希望使用它;那么编写源码时我们就可以使用ES6来编写,之后通过Babel工具,将ES6转成大多数浏览器都支持的ES5的语法
-
-
React 和 Babel的关系
-
默认情况下开发React其实可以不使用babel
-
前提是我们自己使用
React.createElement
来编写源代码,但是它编写的代码非常的繁琐和可读性差。 -
我们就可以直接编写jsx(JavaScript XML)的语法,并且让babel帮助我们转换成
React.createElement
。
-
-
React依赖注入
-
直接CDN引入
- crossorigin的属性的目的是为了解决跨域问题
<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>
-
下载后,添加本地依赖
-
通过npm管理
-
三、React初体验
3.1 Hello World
-
在编写React的script代码中,必须添加
type="text/babel"
,作用是可以让babel解析jsx的语法 -
React 18 之前
ReactDOM.render(<h2>Hello World</h2>, document.querySelector("#root"))
- 引入React 18的依赖会报错
-
React 18
- 通过
ReactDOM.createRoot()
选择一个根 ReactDOM. createRoot
函数:用于创建一个React根,之后渲染的内容会包含在这个根中- 参数:将渲染的内容,挂载到哪一个HTML元素上
<div id="root"></div> <div id="app"></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> <!-- babel --> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script type="text/babel"> // 渲染 Hello World // React 18 之前:React.DOM.render // ReactDOM.render(<h2>Hello World</h2>, document.querySelector("#root")) // React18之后 const root = ReactDOM.createRoot(document.querySelector("#root")) root.render(<h2>Hello World</h2>) const app = ReactDOM.createRoot(document.querySelector("#app")) app.render(<h2>你好 世界</h2>)
- 通过
3.2 Hello React 案例
一个按钮,一段文本,点击按钮修改文本
- 注意:React 修改内容之后需要重新渲染界面
- 基本实现
const root = ReactDOM.createRoot(document.querySelector("#root")) // 将文本定义成一个变量 let message = "Hello World" // 监听按钮的点击 const btnClick = () => { // 修改数据 message = "Hello React" // 重新渲染 rootRender() } // 第一次渲染 rootRender() function rootRender() { root.render(( <div> <h2>{message}</h2> <button onClick={btnClick}>修改文本</button> </div> )) }
四、组件化初体验
4.1 用类的方式封装组件
-
定义一个类(类名大写,组件的名称是必须大写的,小写会被认为是HTML元素),继承自React.Component
-
实现当前组件的render函数
- render当中返回的jsx内容,就是之后React会帮助我们渲染的内容
4.2 数据依赖
-
在组件中的数据,我们可以分成两类:
-
参与界面更新的数据:当数据变量时,需要更新组件渲染的内容
-
不参与界面更新的数据:当数据变量时,不需要更新将组建渲染的内容
-
-
参与界面更新的数据我们也可以称之为是参与数据流,这个数据是定义在当前对象的state中
-
通过在构造函数中 this.state = {定义的数据}
-
当数据发生变化时,可以调用
this.setState
来更新数据,并且通知React进行update操作- 在进行update操作时,就会重新调用render函数,并且使用最新的数据,来渲染界面
-
4.3 事件绑定
-
事件绑定中的this
- 在类中直接定义一个函数,并且将这个函数绑定到元素的onClick事件上,当前这个函数的this指向的是谁呢?
-
默认情况下是undefined
-
为什么是
undefined
呢? -
因为在正常的DOM操作中,监听点击,监听函数中的this其实是节点对象(比如说是button对象)
-
这次因为React并不是直接渲染成真实的DOM,编写的button只是一个语法糖,它的本质是React的Element对象
-
那么在这里发生监听的时候,react在执行函数时并没有绑定this,默认情况下就是一个undefined(在类中的方法,默认在严格模式,严格模式
this
指向undefined
)
-
-
在绑定的函数中,可能想要使用当前对象,比如执行 this.setState 函数,就必须拿到当前对象的this
-
需要在传入函数时,给这个函数直接绑定this(通过bind)
-
类似于下面的写法:
<button onClick={this.changeText.bind(this)}>改变文本</button>
-
4.4 代码实现
// 类组件
class App extends React.Component {
// 组件数据
constructor() {
super()
this.state = {
message: "Hello World"
}
// // 对需要绑定的方法,提前绑定好this
// this.changeText = this.changeText.bind(this)
}
// 实例方法
changeText() {
// setState 是继承 父类中的方法
// 内部完成两件事情:1.修改state中的message 2.自动重新执行render函数
this.setState({
message: "Hello React"
})
}
// 渲染内容
render() {
// console.log(this); // 指向 当前 App
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.changeText.bind(this)}>修改文本</button>
</div>
)
}
}
// 将组件渲染到界面上
const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(<App />)
- 效果
五、demo 练习
5.1 电影列表
- 列表循环使用 数组的
map
方法
// 创建root
const root = ReactDOM.createRoot(document.querySelector("#root"))
// 封装组件
class App extends React.Component {
constructor() {
super()
this.state = {
movies: ["大话西游", "独行月球", "流浪地球", "飞驰人生", "火星救援"]
}
}
render() {
return (
<div>
<h2>电影列表</h2>
<ul>
{this.state.movies.map(movie => <li>{movie}</li>)}
</ul>
</div>
)
}
}
// 渲染组件
root.render(<App/>)
5.2 计数器
const root = ReactDOM.createRoot(document.querySelector("#root"))
class App extends React.Component {
constructor() {
super()
this.state = {
counter: 100
}
this.increment = this.increment.bind(this)
this.decrement = this.decrement.bind(this)
}
increment() {
this.setState({
counter: this.state.counter + 1
})
}
decrement() {
this.setState({
counter: this.state.counter - 1
})
}
render() {
const { counter } = this.state
return (
<div>
<h2>当前计数: {counter}</h2>
<button onClick={this.increment}>+1</button>
<button onClick={this.decrement}>-1</button>
</div>
)
}
}
root.render(<App />)
转载自:https://juejin.cn/post/7141693510104645663