• 黑马React18: 基础Part 1


    黑马React: 基础1

    Date: November 15, 2023
    Sum: React介绍、JSX、事件绑定、组件、useState、B站评论
    Tags: 二刷


    日志:

    11/20: 优化B站评论的案例实现, 增加基础结构和最终结果


    React介绍

    概念: React由Meta公司研发,是一个用于 构建Web和原生交互界面的库

    Untitled

    优势: 1-组件化的开发方式 2-优秀的性能 3-丰富的生态 4-跨平台开发




    开发环境搭建

    使用create-react-app快速搭建开发环境

    create-react-app是一个快速 创建React开发环境的工具,底层由Webpack构建,封装了配置细节,开箱即用

    执行命令

    npx create-react-app react-basic
    
    • 1
    1. npx Node.js工具命令,查找并执行后续的包命令
    2. create-react-app 核心包(固定写法),用于创建React项目
    3. react-basic React项目的名称(可以自定义)

    之后切入到文件夹下, 使用 npm start启动项目

    Untitled

    创建React项目的更多方式: https://zh-hans.react.dev/learn/start-a-new-react-project

    工作方式:

    Untitled

    理解:

    index.js项目入口
    App.js项目的根组件
    index.htmlhtml文件

    项目的根组件以React组件的方式渲染到index.html中

    • Code:

      index.js 简化后的内容

      // 项目的入口 从这里开始
      
      // React必要的两个核心包
      import React from 'react';
      import ReactDOM from 'react-dom/client';
      
      // 导入项目的根组件
      import App from './App';
      
      // 把App根组件渲染到id为root的dom节点上
      const root = ReactDOM.createRoot(document.getElementById('root'));
      root.render(
        
      );
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14



    JSX基础-概念和本质

    什么是JSX

    **概念:**JSX是JavaScript和XML(HTML)的缩写,表示在JS代码中编写HTML模版结构,它是React中编写UI模版的方式

    Untitled

    优势:

    1. HTML的声明式模版写法 2. JS的可编程能力

    JSX的本质

    JSX并不是标准的JS语法,它是JS的语法扩展,浏览器本身不能识别,需要通过解析工具做解析之后才能在浏览器中运行

    Untitled



    JSX基础-高频场景

    JSX中使用JS表达式

    在JSX中可以通过 大括号语法{} 识别 JavaScript中的表达式,比如常见的变量、函数调用、方法调用等等

    1. 使用引号传递字符串
    2. 使用JavaScript变量
    3. 函数调用和方法调用
    4. 使用JavaScript对象

    注意:if语句、switch语句、变量声明属于语句,不是表达式,不能出现在{}中

    案例:

    • Code:

      // 项目的根组件
      // App -> index.js -> public/index.html(root)
      
      const count = 100
      
      function getName() {
        return 'jack'
      }
      
      function App() {
        return (
          
      this is App {/* 使用引号传递字符串 */} {'this is message'} {/* 识别js变量 */} {count} {/* 函数调用 */} {getName()} {/* 方法调用 */} {new Date().getDate()} {/* 使用js对象 */}
      { color: 'red'}}>this is div
      ) } export default 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

    效果:

    Untitled


    JSX中实现列表渲染

    **语法:**在JSX中可以使用原生JS中的map方法遍历渲染列表

    Untitled

    案例:

    const list = [
      { id: 1001, name: 'Vue'},
      { id: 1002, name: 'React'},
      { id: 1003, name: 'Angular'}
    ]
    
    function App() {
      return (
        
    this is App {/* 渲染列表 */}
      {/* { list.map(item =>
    • Vue
    • ) } */} { list.map(item =>
    • { item.name }
    • ) }
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    效果:

    Untitled

    要点:

    1-key值绑定

    作用: 提升性能

    方式: 每一项要加上一个独一无二的key值


    JSX中实现条件渲染

    Untitled

    **语法:**在React中,可以通过逻辑与运算符&&、三元表达式(?:)实现基础的条件渲染

    案例:

    const isLogin = true
    
    function App() {
      return (
        
    {/* 逻辑与 && */} { isLogin && this is span} {/* 三目运算符 */} { isLogin ? this is span :
    this is div
    } {/* 逻辑或 || */} { isLogin || this is span}
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    效果:

    this is spanthis is span


    JSX中实现复杂条件渲染

    Untitled

    需求:列表中需要根据文章状态适配三种情况,单图,三图,和无图三种模式

    解决方案:自定义函数 + if判断语句

    案例:

    // 定义文章类型
    const articleType = 3  // 0 1 3
    
    // 定义核心函数(根据文章类型返回不同的JSX模版)
    
    function getArticleTem () {
      if (articleType === 0) {
        return 
    我是无图文章
    } else if (articleType === 1) { return
    我是单图模式
    } else { return
    我是三图模式
    } } function App () { return (
    {/* 调用函数渲染不同的模版 */} {getArticleTem()}
    ) } export default 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

    效果:

    我是三图模式




    React中的事件绑定

    React 基础事件绑定

    **语法:**on + 事件名称 = { 事件处理程序 },整体上遵循驼峰命名法

    Code:

    function App() {
      const handleClick = () => {
        console.log('button被点击了');
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Res:

    Untitled


    使用事件对象参数

    语法:在事件回调函数中设置形参e

    Code:

    
    function App() {
      const handleClick = (e) => {
        console.log('button被点击了', e);
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Res:

    Untitled


    传递自定义参数

    语法:事件绑定的位置改成箭头函数的写法,在执行clickHandler实际处理业务函数的时候传递实参

    Code:

    function App() {
      const handleClick = (name) => {
        console.log('button被点击了', name);
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Res:

    Untitled

    注意:不能直接写函数调用,这里事件绑定需要一个函数引用


    同时传递事件对象和自定义参数

    语法:在事件绑定的位置传递事件实参e和自定义参数,clickHandler中声明形参,注意顺序对应

    Code:

    function App() {
      const handleClick = (name, e) => {
        console.log('button被点击了', name, e);
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Res:

    Untitled




    React中的组件

    组件是什么

    概念:一个组件就是用户界面的一部分,它可以有自己的逻辑和外观,组件之间可以互相嵌套,也可以复用多次

    Untitled

    组件化开发可以让开发者像搭积木一样构建一个完整的庞大的应用



    React组件

    在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI, 渲染组件只需要把组件当成标签书写即可

    Code:

    function Button() {
      return  
    }
    
    function App() {
      return (
        
    {/* 自闭合 */}
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Res:

    Untitled




    useState

    useState基础使用

    概念:

    useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量, 从而控制影响组件的渲染结果

    Untitled

    本质:和普通变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图)

    const [count, setCount] = useState(0)
    
    • 1

    1- useState是一个函数, 返回值是一个数组

    2-数组中的第一个参数是状态变量, 第二个参数是set函数用来修改状态变量

    3-useState的参数将作为count的初始值

    Case:

    func: 点击按钮, 数值不断增加

    Code:

    import { useState } from "react"
    
    function App() {
      // 1. 调用 useState 添加一个状态变量
      // count 状态变量
      // setCount 修改状态变量的方法
      const [count, setCount] = useState(0)
    
      // 2. 点击事件
      const handleClick = () => {
        setCount(count + 1)
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Res:

    Untitled



    修改状态的规则

    状态不可变

    在React中,状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新

    Untitled

    Untitled

    Case:

    Code:

    import { useState } from "react"
    
    function App() {
      // 1. 调用 useState 添加一个状态变量
      // count 状态变量
      // setCount 修改状态变量的方法
      const [count, setCount] = useState(0)
    
      // 2. 点击事件
      const handleClick = () => {
        setCount(count + 1)
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20


    修改对象状态

    规则:对于对象类型的状态变量,应该始终传给set方法一个全新的对象来进行修改

    直接修改原对象,不引发视图变化

    Untitled

    调用set传入新对象用于修改

    Untitled

    理解: 这里先用展开运算符做个拷贝, 然后再用后面重复属性进行替换即可.

    Case:

    func: 点击按变换名字

    Code:

    import { useState } from "react"
    
    function App() {
    
      const [form, setForm] = useState({ name: 'jack' })
    
      const handleClick = () => {
        setForm({
          ...form,
          name: 'rose'
        })
      }
      return (
        
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Res:

    Untitled

    复习知识点:

    1-…展开匀速符: 深浅拷贝问题

    展开运算符使用的对象如果只是针对简单的一级基础数据,就是深拷贝;
    展开运算符使用的对象内容包含二级或更多的复杂的数据,那就是浅拷贝;




    组件的样式处理

    组件基础样式方案

    React组件基础的样式控制有俩种方式

    1. 行内样式(不推荐)

    Untitled

    1. class类名控制

    Untitled

    Case:

    Code:

    index.js

    import './css/index.css'
    
    const style = {
      color: 'red',
      fontSize: '20px'
    }
    
    function App() {
      return (
        
    {/* 行内样式控制 */}
    { color: 'red'}}>this is span
    {/* 内部样式控制 */}
    this is span
    {/* 外部样式控制 */} this is span
    ) } export default App
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    index.css

    .outer {
      background-color: blue;
    }
    
    • 1
    • 2
    • 3

    Untitled




    案例:B站评论

    效果展示:

    Untitled

    1. 渲染评论列表
    2. 删除评论实现
    3. 渲染导航Tab和高亮实现
    4. 评论列表排序功能实现

    项目基础结构:

    • Code: App.js

      import './App.scss'
      import avatar from './images/bozai.png'
      
      // 当前登录用户信息
      const user = {
        // 用户id
        uid: '30009257',
        // 用户头像
        avatar,
        // 用户昵称
        uname: '黑马前端',
      }
      
      // 导航 Tab 数组
      const tabs = [
        { type: 'hot', text: '最热' },
        { type: 'time', text: '最新' },
      ]
      
      const App = () => {
      
        return (
          
      {/* 导航 Tab */}
      • 评论 {/* 评论数量 */} {10}
      {/* 发表评论 */}
      {/* 当前用户头像 */}
      用户头像
      {/* 评论框 */}