邂逅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




