• React初体验-Hello React的组件化方式-React入门小案例


    React初体验

    接下来我们通过Hello React的案例, 来体验一下React开发模式, 以及jsx的语法

    Hello React案例演练

    第一步: 先引入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>
    
    • 1
    • 2
    • 3
    • 4

    第二步: 这里我们编写React的script代码中,必须添加 type="text/babel",作用是可以让babel解析jsx的语法

    <script type="text/babel">
      // jsx语法编写react代码
    script>
    
    • 1
    • 2
    • 3

    第三步: 创建元素渲染到页面

    React18之前的做法: 通过ReactDOM.render()函数进行渲染的, 需要传入两个参数

    参数一: 要渲染的内容

    参数二: 渲染的内容要挂载到的HTML元素

    
    <div id="app">div>
    
    
    <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>
    
    
    <script type="text/babel">
      // React18之前的做法
      
      ReactDOM.render(<h2>Hello World</h2>, document.querySelector("#app"))
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    React18之后的做法: 通过ReactDOM. createRoot()函数进行渲染, 传入一个参数, 创建一个React根,之后渲染的内容会包含在这个根中(可以有多个根, 一般是一个根)

    
    <div id="app">div>
    <div id="root">div>
    
    
    <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>
    
    
    <script type="text/babel">
      // React18之后的做法
      
      const app = ReactDOM.createRoot(document.querySelector("#app"))
      const root = ReactDOM.createRoot(document.querySelector("#root"))
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    再通过root.render()函数向根组件中渲染元素, 参数传要渲染的元素

    
    <div id="app">div>
    <div id="root">div>
    
    
    <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>
    
    
    <script type="text/babel">
      // React18之后的做法
      const app = ReactDOM.createRoot(document.querySelector("#app"))
      app.render(<h2>Hello React</h2>)
    
      const root = ReactDOM.createRoot(document.querySelector("#root"))
      root.render(<h2>Hello React18</h2>)
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述


    Hello React案例升级

    为了演练React,我们可以提出一个小的需求:

    在界面显示一个文本:Hello World

    点击下方的一个按钮,点击后再将文本改变为Hello React

    在这里插入图片描述

    第一步: 将元素渲染到页面

    jsx中是通过{}绑定变量, 大家先对jsx语法有个体验即可, 后面会详细讲解jsx语法

    
    <div id="app">div>
    
    
    <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>
    
    
    <script type="text/babel">
      const app = ReactDOM.createRoot(document.querySelector("#app"))
    
      // 将文本定义成变量
      let message = "Hello World"
    
      // 第二个小括号表示括号内容是一个整体
      app.render((
        <div>
          <h2>{message}</h2>
          <button>改变文本</button>
        </div>
      ))
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    第二步: 监听按钮点击, 改变message的值

    监听按钮点击jsx是通过onClick绑定一个函数, 注意C一定是大写的

    const app = ReactDOM.createRoot(document.querySelector("#app"))
    
    // 将文本定义成变量
    let message = "Hello World"
    
    // 定义一个函数, 处理按钮点击事件
    function btnClick() {
      // 修改数据
      message = "Hello React"
    
      // 修改完成后需要重新渲染界面
      app.render((
        <div>
          <h2>{message}</h2>
          <button onClick={btnClick}>改变文本</button>
        </div>
      ))
    }
    
    // 第二个小括号表示括号内容是一个整体
    app.render((
      <div>
        <h2>{message}</h2>
        <button onClick={btnClick}>改变文本</button>
      </div>
    ))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    第三步: 简化代码, 上面代码中明显有重复代码, 我们可以抽取到一个函数中

    const app = ReactDOM.createRoot(document.querySelector("#app"))
    
    // 将文本定义成变量
    let message = "Hello World"
    
    // 定义一个函数, 处理按钮点击事件
    function btnClick() {
      // 修改数据
      message = "Hello React"
    
      // 修改完成后需要重新渲染界面
      rootRander()
    }
    
    rootRander()
    // 封装一个渲染函数
    function rootRander() {
      // 第二个小括号表示括号内容是一个整体
      app.render((
        <div>
          <h2>{message}</h2>
          <button onClick={btnClick}>改变文本</button>
        </div>
      ))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Hello React的组件化

    组件化的方式

    Hello React这整个逻辑其实可以看做一个整体,那么我们就可以将其封装成一个组件:

    root.render()函数的参数可以是一个HTML元素, 也可以是一个组件;

    所以我们可以先将之前的业务逻辑封装到一个组件中,然后传入到 root.render 函数中的第一个参数;

    在React中,如何封装一个组件呢?

    React的组件分为两种: 类组件函数式组件

    这里我们暂时使用类的方式封装组件:

    定义一个类(类名大写,组件的名称是必须大写的,小写会被认为是HTML元素),继承自React.Component

    // 类继承自React.Component, 才是组件
    class App extends React.Component{}
    
    • 1
    • 2

    实现当前组件的render函数, render当中返回的jsx内容,就是之后React会帮助我们渲染的内容

    class App extends React.Component {
      // 类中render函数的返回值, 就是要渲染到页面的内容
      render() {
        return (
          <div>
            <h2>Hello World</h2>
            <button>改变文本</button>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    数据依赖

    组件化问题一:数据在哪里定义?

    在组件中的数据,我们可以分成两类:

    参与界面更新的数据:当数据变量时,需要更新组件渲染的内容;

    不参与界面更新的数据:当数据变量时,不需要更新将组建渲染的内容;

    参与界面更新的数据我们也可以称之为是参与数据流,这个数据是定义在当前对象的state中(这个名字是固定的)

    我们可以通过在类的构造器中 this.state = {定义的数据}

    当我们的数据发生变化时,我们可以调用 this.setState 来更新数据,并且通知React进行update操作;

    在进行update操作时,就会重新调用render函数,并且使用最新的数据,来渲染界面

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          message: "Hello World"
        }
      }
    
      // 类中render函数的返回值, 就是要渲染到页面的内容
      render() {
        return (
          <div>
            <h2>{this.state.message}</h2>
            <button>改变文本</button>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    事件绑定

    组件化问题二:事件绑定中的this

    在类中直接定义一个函数,并且将这个函数绑定到元素的onClick事件上,那么问题来了当前这个函数中的this指向的是谁呢?

    默认情况下是undefined

    很奇怪,居然是undefined;

    因为在正常的DOM操作中,监听点击,监听函数中的this其实是节点对象(比如说是button对象);

    这次因为React并不是直接渲染成真实的DOM,我们所编写的button只是一个语法糖,它的本质React的Element对象;

    那么在这里发生监听的时候,react在执行函数时并没有绑定this,默认情况下就是一个undefined;

    我们在绑定的函数中,可能想要使用当前对象,比如执行 this.setState 函数,就必须拿到当前对象的this

    我们就需要在传入函数时,需要给这个函数直接绑定this

    类似于这种写法:

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          message: "Hello World"
        }
      }
    
      btnClick() {
        // setState内部会做两件事情: 1.将state中的值改掉 2.自动执行render函数渲染页面
        this.setState({
          message: "Hello React"
        })
      }
    
      render() {
        return (
          <div>
            <h2>{this.state.message}</h2>
            <button onClick={this.btnClick.bind(this)}>改变文本</button>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    如果有多个按钮, 每次都需要编写this.btnClick.bind(this)是比较麻烦的, 因此React中还有另一种常见的写法, 在constructor在提前绑定this, 这样就可以直接使用方法

    这也是官方文档在的做法

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          message: "Hello World"
        }
        // 为方法提前绑定this
        this.btnClick = this.btnClick.bind(this)
      }
    
      btnClick() {
        this.setState({
          message: "Hello React"
        })
      }
    
      render() {
        return (
          <div>
            <h2>{this.state.message}</h2>
            <button onClick={this.btnClick}>改变文本</button>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    其他案例练习

    电影列表展示

    定义一个数组中存放电影, 再对电影列表进行展示

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          movies: ["大话西游", "黑话律师", "独行月球"]
        }
      }
    
      render() {
        return (
          <div>
            <h2>电影列表</h2>
            <ul>
              <li>{this.state.movies[0]}</li>
              <li>{this.state.movies[1]}</li>
              <li>{this.state.movies[2]}</li>
            </ul>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    但是显然目前这种方法是好的, 我们最好对movies进行遍历展示, 而遍历的方式又有很多种, 先将下面两种方式

    方式一: 对movies数组遍历放入一个新数组中

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          movies: ["大话西游", "黑话律师", "独行月球"]
        }
      }
    
      render() {
        const liEls = []
        for (let item of this.state.movies) {
          const liEl = <li key={item}>{item}</li>
          liEls.push(liEl)
        }
    
        return (
          <div>
            <h2>电影列表</h2>
            <ul>
              {liEls}
            </ul>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    方式二: 使用map直接生成一个新数组, 直接将这个数组放入ul元素中

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          movies: ["大话西游", "黑话律师", "独行月球"]
        }
      }
    
      render() {
    
        return (
          <div>
            <h2>电影列表</h2>
            <ul>
              {this.state.movies.map(item => <li key={item}>{item}</li>)}
            </ul>  
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    计数器的案例

    接下来再使用React做一个熟悉的计数器案例

    class App extends React.Component {
      constructor() {
        super()
    
        this.state = {
          conter: 0
        }
    
        // 为方法绑定this
        this.increment = this.increment.bind(this)
        this.decrement = this.decrement.bind(this)
      }
    
      increment() {
        this.setState({
          conter: this.state.conter + 1
        })
      }
    
      decrement() {
        this.setState({
          conter: this.state.conter - 1
        })
      }
    
      render() {
        return (
          <div>
            <h2>{this.state.conter}</h2>
            <button onClick={this.increment}>+</button>
            <button onClick={this.decrement}>-</button>
          </div>
        )
      }
    }
    
    const app = ReactDOM.createRoot(document.querySelector("#app"))
    app.render(<App/>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
  • 相关阅读:
    将Long类型转化为IP字符串
    《博弈论》— 人生何处不博弈
    实例分割Yolact边缘端部署 (一) 制作自己的数据集
    Flutter:环境搭建、项目创建
    国内设计师经常逛的5个素材网站
    AIGC是不是有点虎头蛇尾
    基础知识——进制 与 进制转换 (C++ 程序)
    【开源】SpringBoot框架开发固始鹅块销售系统
    大数据Doris(十):添加BE步骤
    Spring Security(5)
  • 原文地址:https://blog.csdn.net/m0_71485750/article/details/126585944