学习 react 的第一天_react介绍_react添加依赖及简单案例_JSX语法_JSX属性绑定

一. React在前端重要性

1.1. React基本介绍

  • 官方React定义

    React的官网文档:React 官方中文文档 – 用于构建用户界面的 JavaScript 库

    ◼ 声明式编程:  声明式编程是目前整个大前端开发的模式:Vue、React、Flutter、SwiftUI;  它允许我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染我们的UI界面;

  • Vue/React/Angular市场占率

    • Google指数

    • npm下载指数

    • GitHub star

    • HackerRank

  • React的重要性

1.2. 如何系统的学习React

  • 官方文档

  • 看书学习

  • 开源项目

  • 当前课程

二. 邂逅React开发

2.1. React介绍以及特点

  • 声明式编程

  • 组件化开发

  • 一次学习, 多平台适配

2.2. Hello React

2.2.1. React有三个依赖

  • React:包含react所必须的核心代码

  • React-DOM:react渲染在不同平台所需的核心代码

  • Babel:将 jsx 转换成 React 代码的工具

◼ 第一次接触React会被它繁琐的依赖搞蒙,居然依赖这么多东西: (直接放弃?)

 对于Vue来说,我们只是依赖一个vue.js文件即可,但是react居然要依赖三个包。

 其实呢,这三个库是各司其职的,目的就是让每一个库只单纯做自己的事情;

 在React的0.14版本之前是没有react-dom这个概念的,所有功能都包含在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.1.1 Beble 和 react 的关系

◼ babel是什么呢?

 Babel ,又名 Babel.js。

 是目前前端使用非常广泛的编译器、转移器。

 比如当下很多浏览器并不支持ES6的语法,但是确实ES6的语法非常的简洁和方便,我们开发时希望使用它。

 那么编写源码时我们就可以使用ES6来编写,之后通过Babel工具,将ES6转成大多数浏览器都支持的ES5的语法。

◼ React和Babel的关系:

 默认情况下开发React其实可以不使用babel。

 但是前提是我们自己使用 React.createElement 来编写源代码,它编写的代码非常的繁琐和可读性差。

 那么我们就可以直接编写jsx(JavaScript XML)的语法,并且让babel帮助我们转换成React.createElement。

三、运用react

3.1 添加依赖

<!-- 添加依赖 -->
  <!-- 依赖三个包 -->
  <!-- 1.引入React核心库-得到一个React对象 -->
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <!-- 2.引入React扩展库-得到ReactDOM对象 -->
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <!-- 3.引入babel-作用是将jsx转化为浏览器能够识别的js语法 -->
  <!-- 注:若是在开发过程中使用到了jsx语法(或使用es6等js高级语法)则引入babel,否则不需要引入 -->
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

3.2 运行出 hello word

<!-- type="text/babel" 这句话必须加上,否则会报错  -->
  <script type="text/babel">
    // 编写 react 代码(jsx 语法)
    // jsx默认情况下浏览器不识别,所以需要 babel 依赖

    // 渲染一个 HelloWord
    // React18之前:reactDOM.render
    // ReactDOM.render(<h2>Hello Word</h2>, document.querySelector('#root'))

    // React18之后:reactDOM.createRoot
    const root = ReactDOM.createRoot(document.querySelector('#root'))
    root.render(<h2>Hello Word</h2>)
    const app = ReactDOM.createRoot(document.querySelector('#app'))
    app.render(<h2>Hello React</h2>)
  </script>

3.4 react 数据的绑定

<script type="text/babel">
    // 编写 react 程序
    const root = ReactDOM.createRoot(document.querySelector('#root'))

    // 获取 DOM 元素的方法
    // 1.将文本定义成变量
    let message = "Hello Word"

    // 2.监听按钮的点击 此时需要重新渲染
    function btnClick() {
      message = "hello react"
      // 重新渲染
      rootRender()
    }
    root.render((
      <div>
        <h2>{message}</h2>
        <button onClick={btnClick}>修改文本</button>
      </div>
    ))

    // 3. 封装一个渲染函数
    function rootRender() {
      root.render((
      <div>
        <h2>{message}</h2>
        <button onClick={btnClick}>修改文本</button>
      </div>
    ))
    }

    rootRender()
  </script>

第一步:在界面上通过React显示一个Hello World

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

◼ ReactDOM. createRoot函数:用于创建一个React根,之后渲染的内容会包含在这个根中

 参数:将渲染的内容,挂载到哪一个HTML元素上 ✓ 这里我们已经提定义一个id为app的div

◼ root.render函数:

 参数:要渲染的根组件 ◼ 我们可以通过{}语法来引入外部的变量或者表达式

四、通过组件封装 react

4.1 封装一个组件

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

 我们说过root.render 参数是一个HTML元素或者一个组件;

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

◼ 在React中,如何封装一个组件呢?这里我们暂时使用类的方式封装组件:

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

 2.实现当前组件的render函数

✓ render当中返回的jsx内容,就是之后React会帮助我们渲染的内容

4.2 如何实现组件的数据依赖

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

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

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

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

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

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

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

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

4.3 难点 this 的指向问题

可参考官方文档中的事件处理 事件处理 – React

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

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

◼ 默认情况下是undefined

 很奇怪,居然是undefined;

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

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

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

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

 我们就需要在传入函数时,给这个函数直接绑定this  类似于下面的写法:改变文本

// 使用组件重构代码
    // 类组件和函数式组件 继承 react 里面的方法才是一个组件
    class App extends React.Component {
      // 组件数据
      constructor() {
        // 有继承就要调用 super
        super()
        // 如果有动态数据的更新,需要放在 sate 属性当中
        this.state = {
          message: "Hello Word"
        }

        // 对需要绑定的方法,提前绑定好 this
        // <button onClick={this.btnClick.bind(this)}>修改文本</button> 这里就不需要重新绑定了
        this.btnClick = this.btnClick.bind(this)
      }
      // 组件方法(实例方法)
      btnClick() {
        console.log("btnClick:", this); // undefined 通过 bind(this)修改this的指向,才能拿到组件的this
        // 内部完成了两件事情: 1.将 state 中的message的值修改掉  2.自动执行 render 函数,不需要重新调用
        this.setState({
          message: "Hello React"
        })
      }


      // 渲染内容 render 方法,调用render函数返回内容
      // 这里的 btnClick不可以加小括号调用方法,因为此时返回的是undefined
      // bind(this) 修改 this 的指向
      render() {
        return (
          <div>
            <h1>{this.state.message}</h1>
            <button onClick={this.btnClick}>修改文本</button>
          </div>
        )
      }
    }


    // this 绑定的问题
   /*  const app = new App()
    const foo = app.btnClick
    // 在严格模式下,默认绑定的 this 指向 undefined
    foo(); // 默认绑定 =》 window => 严格模式下 => undefined

    function bar() {
      console.log("bar:" , this);
    }
    bar()  // bar : undefined */
    
    // 将组件渲染到界面上
    const root = ReactDOM.createRoot(document.querySelector('#root'))
    root.render(<App/>)

4.4. 案例二: 电影列表渲染

<div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    // 1.创建root
    const root = ReactDOM.createRoot(document.querySelector('#root'))

    // 封装组件
    class App extends React.Component {
      constructor() {
        super()
        this.state = {
          movies: ['大话西游', '冰雪奇缘', '独行月球', '深海']
        }
      }

      render() {
        // 1.对 movies 进行 for  循环
        /* const liEls = []
        for(let i = 0; i < this.state.length; i++) {
          const movie = this.state.movies[i]
          const liEl = <li>{movie}</li>
          liEls.push(liEl)
        } */

        // 2.movies 数组 -> liEls 数组, 使用 map 映射,可以直接放入结构中
        // const liEls = this.state.movies.map(item =>  <li>{item}</li>)
        return (
          <div>
            <h2>电影列表</h2>
            <ul>
              {this.state.movies.map(item =>  <li>{item}</li>)}
            </ul>
          </div>
        )
      }
    }

    // 2.渲染组件
    // jsx -> React.createElement
    root.render(<App/>)
  </script>

4.5. 案例三: 计数器案例

// 创建 root
    const root = ReactDOM.createRoot(document.querySelector('#root'))

    // 创建组件
    class App extends React.Component {
      constructor() {
        super()
        this.state = {
          message: "Hello",
          counter: 100
        }
        // 修改 this 的指向
        this.increment = this.increment.bind(this)
        this.decrement = this.decrement.bind(this)
      }
      
    
      render() {
        return (
          <div>
            <h1>当前计数: {this.state.counter}</h1>
            <button onClick={this.increment}>+1</button>
            <button onClick={this.decrement}>-1</button>
          </div>
        )
      }

      // 组件的方法
      increment() {
        console.log('increment');
        this.setState({
          counter: this.state.counter + 1
        })
      }

      decrement() {
        console.log('decrement');
        this.setState({
          counter: this.state.counter - 1
        })
      }
    }

    // 渲染组件
    root.render(<App/>)

4.6 VSCode 代码片段

第一步,复制自己需要生成代码片段的代码; 

第二步,https://snippet-generator.app/在该网站中生成代码片段;

第三步,在VSCode中配置代码片段;

五、JSX语法

JSX其实是嵌入到JavaScript中的一种结构语法;

5.1 JSX的书写规范:

 JSX的顶层只能有一个根元素,所以我们很多时候会在外层包裹一个div元素(或者使用后面我们学习的Fragment);

 为了方便阅读,我们通常在jsx的外层包裹一个小括号(),这样可以方便阅读,并且jsx可以进行换行书写;

 JSX中的标签可以是单标签,也可以是双标签;

        ✓ 注意:如果是单标签,必须以/>结尾;

JSX的注释: {/* 这里写JSX的注释 */}

5.2 JSX嵌入变量作为子元素

 情况一:当变量是Number、String、Array类型时,可以直接显示

 情况二:当变量是null、undefined、Boolean类型时,内容为空;

        ✓ 如果希望可以显示null、undefined、Boolean,那么需要转成字符串;

        ✓ 转换的方式有很多,比如toString方法、和空字符串拼接,String(变量)等方式;

 情况三:Object对象类型不能作为子元素(not valid as a React child)

        ✓ 要想显示一个东西可以用 Object.keys(friend)[0]

const {message, names} = this.state
        const {aaa,bbb,ccc} = this.state
        const {friend} = this.state

 {/* 1:当变量是Number、String、Array类型时,可以直接显示
                2:当变量是null、undefined、Boolean类型时,内容为空;
              ✓ 如果希望可以显示null、undefined、Boolean,那么需要转成字符串;
              ✓ 转换的方式有很多,比如toString方法 aaa.toString()、和空字符串拼接 bbb+'',String(变量)等方式String(ccc);
            */}
            <h1>{message}</h1>
            <h1>{names}</h1>
            <h1>{String(aaa)}</h1> 
            <h1>{bbb+''}</h1> 
            <h1>{ccc.toString()}</h1> 

            {/* 3: Object 类型不能作为子元素进行显示
              要想显示一个东西可以用 Object.keys(friend)[0]
            */}
            <h1>{Object.keys(friend)[0]}</h1>

JSX嵌入表达式

 运算表达式

 三元运算符

 执行一个函数

{

const {firstName, lastName} = this.state
        const fullName = firstName + lastName
        const {age} = this.state
        const ageText = age>18?'成年人':'未成年人'
        const liEls = this.state.movies.map(item => <li key = {item}>{item}</li>)

/* 4:可以插入对应的表达式 */}
            <h1>{firstName + lastName}</h1>
            <h1>{fullName}</h1>

            {/* 5:可以插入三元运算符 */}
            <h1>{age>18?'成年人':'未成年人'}</h1>

            {/* 6: 可以调用方法获得结构  */}
            <ul>{liEls}</ul>
            <ul>{this.state.movies.map(item => <li>{item}</li>)}</ul>
            <ul>{this.getMovieEls()}</ul>

5.3 jsx绑定属性

 比如元素都会有title属性

 比如img元素会有src属性

 比如a元素会有href属性

 比如元素可能需要绑定class

 比如原生使用内联样式style

// 创建组件
    class App extends React.Component {
      constructor() {
        super()
        this.state = {
          // 1.基本属性的绑定
          title: 'https://pics3.baidu.com/feed/5ab5c9ea15ce36d3f49673ee881dfb8ceb50b15c.jpeg@f_auto?token=a8163e55915bac4a83acebbd2c2bcf70',
          imgURL: 'https://pics3.baidu.com/feed/5ab5c9ea15ce36d3f49673ee881dfb8ceb50b15c.jpeg@f_auto?token=a8163e55915bac4a83acebbd2c2bcf70',
          href: "http://www.baidu.com",

          // 2.class 属性的绑定
          isActive: true,

          // 3.style 属性的绑定
          styleColor: {
            color: "red", fontSize: "30px"
          }
        }
      }
      
    
      render() {
        const {title,imgURL, href, isActive,styleColor} = this.state

        // 需求:isActive: true -> active
        // 1.绑定的写法一:字符串的拼接
        const className = `abc cba ${isActive ? 'active' : ''}`
        // 2.绑定的方法二:将所有的class放在数组中
        const classList = ['abc', 'cba']
        if(isActive) classList.push('active')
        // 3.绑定的方法三:第三方的库 classnames -> npm install classnames
        return (
          <div>
            {/*1.基本属性绑定*/}
            <h2 title={title}>我是 h2 元素</h2>
            <img src={imgURL} alt=""/>
            <a href={href}>百度</a>

          {/* 2.class 属性绑定: 最好使用 className
                classList 不能用逗号分隔,最好用空格分隔,所以用 join(" ")
          */}
          <h2 className={className}>哈哈哈</h2>
          <h2 className={classList.join(" ")}>哈哈哈</h2>

          {/* 3. style 属性的绑定*/}
            <h2 style={{color: "red", fontSize: "30px"}}>呵呵呵呵</h2>
            <h2 style={styleColor}>呵呵呵呵</h2>
            
          </div>
        )
      }

    }

    // 创建 root 根,渲染组件
    const root = ReactDOM.createRoot(document.querySelector('#root'))
    root.render(<App/>)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值