React

特点

  • 声明式UI
  • 组件化
  • 一次学习,跨平台编写

JSX

在React中创建HTML结构

使用js表达式

{JS 表达式}

  • 识别常规变量
  • 原生js方法调用
  • 三元运算符
JSX 列表渲染

map 方法

key仅在内部使用,不会出现在真实的dom结构中

1
2
3
4
<ul>
{ items.map(item => <li key = {item.id}>{item.name}</li>)}
<li>
</ul>
条件渲染
  • 三元运算符
  • 逻辑&&运算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div> 
{ flag ? <span>true</span> : null}
</div>

<div>
{ flag && <span>true</span>}
</div>

//复杂情况,用函数写逻辑,模版中调用函数
const getFlag = (type)=>{
if(type === 1){
return <h1>h1</h1>
}
if(type === 2){
return <h2>h2</h2>
}
}
<div>
{ getFlag(1) }
</div>


样式处理
  • 行内样式 - 在元素上绑定一个style属性
  • 类名样式 - 在元素上绑定一个className属性
1
2
3
<span style = {{color : "red"}}>11 </span>
<span className = 'class'>11 </span>
<span className = {flag ? 'class' :'' }>11 </span>
注意事项
  • 只能有一个根节点
  • 所有标签都要闭合
  • 属性名采用驼峰
  • 支持多行 用()包裹

组件

函数组件
  • 组件名称首字母大写
  • 必须要有返回值
  • 组件可以像HTML标签一样渲染到页面,需要闭合
类组件
1
2
3
4
5
class HelloComponent extends React.Component{
render(){
return <div>class Component</div>
}
}
  • 组件名称首字母大写
  • 需要继承父类
  • 必须要render 且有返回值

事件绑定

  • 语法

  • 传参

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <div onClick = {()=>{console.log(111)} }>222</div>

    function Hello () {
    const fun1 = (e,msg) => {
    console.log(msg)
    }

    return <div onClick = {(e)=>{fun1(e, "msg")} }>222</div>
    }

组件状态

  • 定义状态必须通过state实例的方法

  • 不能直接赋值,通过setState方法

  • 不要直接修改状态的值,而是基于当前状态创建新的状态值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    this.setState({
    count: this.state.count + 1,
    //add
    list: [...this.state.list, 4],
    //delete
    list: this.state.list.filter((item) => item != 2)
    people:{
    ...this.state.people,
    //重新覆盖
    name: "newName"
    }
    })

表单组件

  • 受控组件

    input框自己的状态被React组件状态控制

  • 非受控组件

    通过dom方式获取文本值

组件通信

组件之间数据交流

  • 父传子

    class : this.props.msg

    function: props.msg

    props 是只读的,可以传递任何数据,可以解构赋值

    • 子传父 - 子调用父的函数,把数据作为参数传入。
  • 兄弟互传 - 自定义事件模式产生技术方法eventBus / 通过父组件

  • 其他关系 - mobx / redux / 基于hook的方案

  • context

    • 调用createContext方法得到providerconsumer
    • 通过provider 包裹顶层组件 value属性绑定数据
    • 通过consumer包裹底层组件(value => 消费数据
  • children

    在组件中写入东西(普通文本,普通标签元素,函数,JSX ),都会作为children属性传到组件中

  • props 校验

生命周期

只有类组件有生命周期(类组件需要实例化)

image-20230328163906053

生命周期图

挂载阶段
钩子函数 触发时机 作用
constructor 创建组件时,最先执行,初始化的时候只执行一次 1. 初始化state
2. 创建ref
3. 使用bind解决this指向问题等等
render 每次组件渲染都会触发 渲染UI(注意:不能在里面调用setState())
componentDidMount 组件挂载(完成DOM渲染)后执行,初始化的时候执行一次 1.发送网络请求
2.DOM操作
更新阶段
钩子函数 触发时机 作用
render 每次组件渲染都会触发 渲染UI(与 挂载阶段 是同一个render)
componentDidUpdate 组件更新后(DOM渲染完毕) DOM操作,可以获取到更新后的DOM内容,不要直接调用setState
卸载阶段
钩子函数 触发时机 作用
componentWillUnmount 组件卸载(从页面中消失) 执行清理工作(比如:清理定时器等)

Hooks

本质:一套能够使函数组件更强大,更灵活的“钩子”

UI = f(data)

解决问题
  1. 组件的逻辑复用
  2. class组件自身的问题
useState
1
2
3
4
5
6
7
8
9
10
import {useState} from 'react'

function App(){
const [count, setCount] = useState(0)
return (
<div>
<button onClick = {() => setCount(count + 1)}>{count} </button>
</div>
)
}
  1. useState传的参数,为初始值,只有首次渲染生效
  2. 写法是一个数组的解构赋值
  3. 变量名可以自定义
  4. 位置不能换
  5. setCount 用新值换原值
  6. 两个绑定使用
  7. 不能嵌套在if/for/或者其他函数中
  8. 可以用箭头函数作为参数
useEffect
  1. 理解函数副作用

    1. 除了主作用就是副作用

      主作用就是根据数据渲染UI

    2. 常见副作用

      • 数据请求 ajax
      • 手动修改dom
      • localstorage操作
  2. 基础使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import {useState, useEffect} from 'react'

    function App(){
    const [count, setCount] = useState(0)

    useEffect(() => {
    //定义副作用
    document.title = count
    })
    useEffect(() => {
    //定义副作用 空数组依赖项
    document.title = count
    }, [])
    return (
    <div>
    <button onClick = {() => setCount(count + 1)}>{count} </button>
    </div>
    )
    }

    依赖项控制副作用的执行时机

    1. 默认 首次渲染执行一次,当组件更新,副作用也会执行

    2. 参数,空数组 首次渲染执行一次

    3. 特定依赖项,在首次渲染执行,在依赖项变化后,也执行一次

  3. 清除副作用

    return 一个箭头函数,在组件销毁时会执行

useRef

获取真实的dom或组件实例

1
2
3
4
5
6
7
8
9
10
import {useEffect, useRef} from "react"

function App(){
const h1Ref = useRef(null)
console.log(h1Ref.current)
return {
<h1 ref = {h1Ref}>1</h1>
}
}
export default App
useContext

实现步骤

  • 使用createContext创建context对象
  • 在顶层通过Provider提供数据
  • 在底层通过useContext获取数据

Router

1
yarn add react-router-dom@6
  1. BrowerRouter \ HashRouter
  2. Link <Link to = '/'> </Link>
  3. Routes
  4. Route <Route path = '/' element = {<Home/>}/>
编程式跳转

useNavigate

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
import {useNavigate,useSearchParams, useParams} from 'react-router-dom'

function App () {
const navigate = useNavigate()

function goAbout(){
navigate('/about')
//可以增加一些配置 或者 参数
navigate('/about', {replacr: true})
navigate('/about?id = 1001')
let [params] = useSearchParams()
let id = params.get('id')

navigate('/about/1001')
//需要动态路由
//<Route path='/about/:id' />
let params = useParams()
let id = params.id
}

return (
<button onClick = {goAbout}> </button>
)
}

export default App
嵌套路由

二级路由出口

默认二级

<Route index element = {}>

404 路由

<Route path='*' element = {<NotFound/>}>

Mobx

响应式状态管理

  • 优势
    • 简单
    • 轻松实现最优渲染
    • 架构自由