React基础与实践 | 青训营笔记

91 阅读4分钟

React哲学与特点

所有图片来自 字节前端训练营 - React 基础与实践.pdf - 飞书云文档 (feishu.cn)

此文档是对对应课程 React 基础与实践 - 掘金 (juejin.cn) 的笔记

react是使用 JavaScript 构建 快速响应 的 Web应用 的首选方式之一。

React实现快速响应的原因:

对影响浏览器性能的2个主要因素做出了解决方案:

  • 等待下载资源
    • 一次性请求太多资源:React.lazy
    • 下载速度慢:React.Suspense
    • 请求错误:ErrorBoundary
  • 大部分事件下浏览器是单线程执行的
    • JS执行阻塞了页面渲染:时间切片、异步更新
    • 计算布局大小:React Fiber

React更新流程

image.png

React基础

image.png

  • 架构的角度来看

通常使用JSX作为React描述Web标签(或组件)的方式以简化React.createElement(type, config, childrens)的写法。 但浏览器不能直接识别JSX,因此需要使用babel工具将JSX转化为JS。

此外,实现了对加载速度慢(或下载内容过多)、访问不存在资源的优化。

  • 组成的角度

1.界面的展示

单纯从界面的组成:将页面拆分为若干部分用组件分别实现,再抽象出可复用的UI形成可复用组件,对于可复用的逻辑拆分为高阶组件或hook函数。

对于单页面应用SPA:React Router实现前端路由;

2.状态管理

  • React Redux
  • context

image.png

组件的角度:

  • 状态管理
  • 直接使用DOM
  • 组件通信
  • 性能优化

react组件的3大属性:state/ref/props

状态管理: 其中 state 存储可变状态;ref存储持久化数据(即在组件重新渲染后仍能保存的数据)(可变)(同时,修改ref的值也不会引起组件的重新渲染)

DOm的使用:ref也可以得到DOM对象,实现对DOM的直接调用

组件通信:通过 props(父子间) context redux(跨组件、跨页面)

性能优化:此处从减少不变元素的重复渲染角度出发

const MemoMyComponent = React.memo(MyComponent)
// 此时使用MemoMyComponent组件,当传入其中的props不变时,不会重新渲染
const newValue = useMemo(() => value, [dependences])
// 若dependences不变,则返回原有的值
const newFn = useCallback(() => fn, [dependences])
// 若dependences不变,则返回原有的函数
// 等价
const newFn = useMemo(() => {() => fn}, [dependences])

一个样例

import React, { useState, useCallback, memo } from 'react'
// 子组件Button,点击增加父组件的计数值,但本身 不需要 改变
// 因此,需要其传入的参数 handClick 不变
const MyButton = memo((handleClick) => {
    return (
        <Button onClick={handleClick}></Button>
    )
})

const Counter = () => {
    // 记录点击次数
    const [count, onSetCount] = useState(0);
    // 使用useCallback使得每次返回相同的函数(相同的对象引用)
    const handleClick = useCallback(() => {
        increaseCount(count => count + 1);
    },[]);
    
    return (
        <div>
            <span>{count}</span>
            <MyButton handleClick={ handleClick }>Click</MyButton>
        </div>
    )
}

点击按钮,增加count的计数。

由于每次增加计数改变了state的值,导致父组件Counter的重新渲染

因此子组件MyButton也重新渲染.

为了优化不需要重新渲染的子组件MyButton,对其使用了React.memo,同时需要配合使用useMemouseCallback使传入子组件props中的变量或函数保持不变以避免重新渲染。

useMemouseCallback只是用于值不变时返回原值(不变的对象引用/指针)。需要配合React.memo返回不变的依赖,实现减少布标要的渲染。

但同时也增加了创建函数或变量的次数,需要具体判断是否有效优化性能。

参考:

React.memo - 掘金 (juejin.cn)

重新认识 React.useCallback - 掘金 (juejin.cn)

React—攻克Hooks之useMemo - 知乎 (zhihu.com)

类组件函数组件的对比

类组件:

  • 继承React.Component实现render方法
  • this
  • 生命周期函数

函数组件:

  • 无生命周期
  • 借助useHooks实现state和在指定生命周期执行函数
  • 直接返回JSX

函数组件更灵活,代码量少;可以将逻辑抽取出hook实现复用。

另:组件是对UI实现抽取复用;hook是对逻辑实现抽取复用。hook可以是组件的一部分,即粒度更小。

关于hook

原则:

  • 只能在函数组件中调用hook
  • 自定义hook必须以use开头
  • 必须在顶层调用hook

实际上,与react识别到hook的方式有关。

在顶层调用的原因:

react以数组的方式保存各个state,即每次重新渲染时调用useState的顺序不能改变。

关于hook的过期闭包问题:

JS的闭包是一个函数使用了其上层环境的变量
而当上层环境的变量更新,闭包没有同步更新时,就出现了过期闭包问题。

修改状态是直接对setState进行的,因此在使用useEffect时,可能出现使用旧的state值,此时将其加入依赖即可。

useEffect(() => {}, [dependences])

常见API

image.png

image.png