二、React进阶特性

一、学习目标

  • 掌握 ref、forwardRef、suspense、lazy 等特性
  • 深入理解 React Hooks,能根据实际业务需求封装自定义 Hook​    
  • 深入理解 React 样式体系方案:module css、css in js 
  • 掌握 React + Typescript 开发范式
  • React 性能优化技巧:如代码拆分、懒加载、React.memo、useMemo 和 useCallback 等​
  • 了解 React19 新特性

二、补充资料

  • Suspense 官方文档:https://zh-hans.react.dev/reference/react/Suspense​    
  • 阿里 hooks 库:https://ahooks.js.org/zh-CN/​  
  • React 生态:https://github.com/enaqx/awesome-react​    
  • React 秘笈:https://react-typescript-cheatsheet.netlify.app/​  
  • immer:https://github.com/immerjs/immer​    
  • React + Typescript 类型工具小抄:https://github.com/typescript-cheatsheets/utilities​  
  • 构建产物兼容支持等级,browserslist 方案:https://github.com/browserslist/browserslist​    ​

三、面试真题

1、说说你对 React Hooks 的理解

2、说说 React Suspense

四、React进阶特性

用vite快速创建一个react项目

1、ref

(1)、我们在开发中不再推荐使用DOM提供的api去获取和操作DOM元素了,如document.getElementById等

import React, { useRef, useEffect } from "react"
 
export const RefDemo = () => {
    // 1、通过创建ref对象的方式获取dom实例
    // const inputRef = React.createRef<HTMLInputElement>(null);
    // 2、使用hooks方式获取dom实例
    const inputRef = useRef<HTMLInputElement>(null);
    // 只有在元素挂载完毕之后才能获取到该节点,可以等同于componentDidMount 
    useEffect(()=>{
        if(inputRef.current){
             inputRef.current.focus()
        }
    }, [])
    
    return (
        <div>
            {/* form元素获取 dom 实例 */}
            {/* canvas 元素获取 dom 实例 */}
            <input ref={inputRef} />
        </div>
    )
}

(2)、用来存储值,但是不能是状态

之前

组件内部的数据一定要在组件内部定义,不要在组件外部定义

import React, { useRef, useEffect } from "react"
// 不要随意定义变量
// let timer = null
const Test = () => {
    // 不要随意定义变量
    let timer = null
    useEffect(() => {
        timer = setInterval(() => {
            console.log('1')
        }, 1000)
        return () => {
            clearTimeout(timer)
        }
    }, [])
    return (
        <div></div>
    )
}

现在

const Test = () => {
    const timerRef = useRef(null)
    useEffect(() => {
        timerRef.current = setInterval(() => {
            console.log('1')
        }, 1000)
        return () => {
            clearTimeout(timerRef.current)
        }
    }, [])
    return (
        <div></div>
    )
}

对象的方式存储ref

export const Test = () => {
    const inputsRef = useRef<Record<string, HTMLInputElement | null>>({})
    useEffect(() => {
        console.log(inputsRef.current)
        console.log(inputsRef.current.input1.value)
    }, [])
    
    return (
        <div>
            {/* 回调函数直接赋值 */}
            <input ref={(el) => inputsRef.current['input1'] = el} />
            <input ref={(el) => inputsRef.current['input2'] = el} />
            <input ref={(el) => inputsRef.current['input3'] = el} />
        </div>
    )
}
export const Test = () => {
    const inputsRef = useRef({})
    useEffect(() => {
        console.log(inputsRef.current)
    }, [])

    return (
        <div>
            {
                ['input1', 'input2', 'input3', 'input4'].map((item) => (
                    <input ref={(el) => inputsRef.current[item] = el} />
                ))
            }
        </div>
    )
}

2、suspense

(1)、动态加载组件,用Suspense来做过度过程的降级处理loading(异步组件)

代码拆分 = 动态加载异步组件 + suspense

Input.js

const Input = () => {
    const inputRef = useRef(null)
    useEffect(()=>{
        if(inputRef.current){
            inputRef.current.value = 666
        }
    }, [inputRef])
    return (
        <div>
            <input type="text" ref={node=>inputRef.current = node} />
        </div>
    )
}
export default Input;
// 静态导入组件,性能不好,假如静态组件里面有个大体积图形,如果目前我不想渲染Input组件,那我还需要加载这个大体积图形的代码吗?
// import Input from './Input'
const Input = lazy(() => import('./Input')); //按需加载 默认导入
const Test = () => {
    return (
        <Suspense fallback={<div>Loading...</div>}>
            <Input />
        </Suspense>
    )
}

(2)、动态加载数据,等待异步处理完之后,再来渲染内部的组件(带有异步操作组件)

import React, { useRef, useEffect, Suspense, use } from "react"
let cache = new Map();
const fetchDate = (url) => {
    if (!cache.has(url)) {
        cache.set(url, getData(url))
    }
    return cache.get(url)
}
async function getData(url){
    if (url === "/the-beatles/albums") {
        return await getAlbums();
    } else if (url === "/the-beatles/bio") {
        return await getBio();
    }else{
        throw new Error("url is not valid")
    }
}
async function getBio(){
    await new Promise(resolve=>{
        setTimeout(resolve, 3000)
    })
    return 'Bio'
}
async function getAlbums(){
    await new Promise(resolve=>{
        setTimeout(resolve, 3000)
    })
    return [
        {​ id: 13,​ title: 'Let It Be',​ year: 1970​}, 
        {​ id: 12,​ title: 'Abbey Road',​ year: 1969​}
    ] 
}
function Albums({ artistId, type }) {​ 
       const albums = use(fetchData(`/${artistId}/albums`));​ 
       return (​ 
         <ul>​ 
           {albums.map(album => (​ 
             <li key={album.id}>​ 
               {album.title} ({album.year})​ 
             </li>​ 
           ))}​ 
         </ul>​ 
       );​ 
     }
const Test = () => {
    return (
        <Suspense fallback={<div>Loading...</div>}>
            <Albums artistId="the-beatles"/>
        </Suspense>
    )
}

3、forwardRef(before React19)

父组件给子组件传递ref

React19,使用props传递ref

interface InputsProps {
    value?: string;
    ref?: Ref<HTMLInputElement>;
}
const Input = ({ ref }: InputsProps) => {
    return (
        <div>
            <input ref={ref} />
        </div>
    )
}
const Test = () => {
    const inputRef = useRef(null)
    return (
        <div>
            <Input ref={inputRef} />
        </div>
    )
}

4、memo

优化子组件更新的hook

const Child = memo(({age, name}) => {
     return (
        <div>
            <div>{age}</div>
            <div>{name}</div>
        </div>
     )
}, (prevProps, nextProps)=>{// 判断props是否发生了变化,true表示props更新前后结果相等,不渲染
    // console.log(prevProps, nextProps)
    return prevProps.age === nextProps.age
})
const Father = () => {
    const [age, setAge] = useState(0)
    const [name, setName] = useState('pig')
    return (
        <div>
            <Child name={name} age={age} />
            <button  onClick={()=>setAge(c=>c+1)}>age</button>
            <button  onClick={()=>setName("pitaya")}>name</button>
        </div>
    )
}

5、useLayoutEffect

与useEffect用法一样,但是它是在dom变更之后同步执行的,比useEffect先执行

const Test = () => {
    const ref = useRef(null)
    useEffect(() => {
        if (ref.current) {
            ref.current.style.backgroundColor = 'yellow';
        }
        console.log('useEffect')
    }, [ref])
    useLayoutEffect(() => {
        if (ref.current) {
            ref.current.style.backgroundColor = 'yellow';
        }
        console.log('useLayoutEffect')
    }, [ref])
    // useLayoutEffect
    // useEffect
    return <div ref={ref}>Layout Effect</div>;
}

6、useId

生成唯一的id,具体用法如下

const Test = () => {
    const firstNameId = useId()
    const lastNameId = useId()
    useEffect(() => {
        console.log(firstNameId, lastNameId)
    }, [firstNameId, lastNameId])
    return (
        <div>
            <label htmlFor={firstNameId}>firstName</label>
            <input id={firstNameId} type="text" />
            <label htmlFor={lastNameId}>lastName</label>
            <input id={lastNameId} type="text" />
        </div>
    )
}

7、useTransition

处理ui过渡

8、自定义hook demo

状态和ui在一个组件里面,我们将它解耦

状态封装在hooks里面,ui封装在ui组件里面

const Input = () => {
    const [value, setValue] = useState("");
    const handleChange = (e: React.changeEvent<HTMLInputElement>) => {
        setValue(e.target.value)
    }
    return (
        <div>
            <input type="text" value={value} onChange={handleChange}/>
        </div>
    )
}
const Test = () => {
    return (
        <div>
            <Input />
        </div>
    )
}

封装之后

const useControlValue = (initialValue: string) => {
        const [value, setValue] = useState(initialValue);
        const handleChange = (e: React.changeEvent<HTMLInputElement>) => {
        setValue(e.target.value)
    }
    return {
        value,
        handleChange
    }
}
const Test = () => {
    const {value, handleChange} = useControlValue
    return (
        <div>
           <input type="text" value={value} onChange={handleChange}/>
        </div>
    )
}

9、样式方案

  • 内联样式:简单直观,适合动态样式和小型项目,但复用性差,功能有限。​    
  • CSS Modules:提供局部作用域,支持所有 CSS 功能,适合中大型项目,但配置复杂。​  
  • CSS-in-JS:组件化样式,动态生成样式,功能强大,适合大型项目,但性能开销和学习成本较高。​
  • Tailwind CSS:实用优先,快速开发 UI,适合所有项目,但类名冗长,灵活性受限。
内联样式
  • 样式复用差:无法轻易复用样式,导致样式代码重复。​    
  • 缺乏伪类和伪元素支持:无法使用 :hover、:active 等伪类和伪元素。​    
  • CSS 功能有限:许多 CSS 功能(如媒体查询、关键帧动画等)不能使用。​    ​
const divStyle = {
    color: 'blue',
    backgroundColor: "pink"
}
const InlineStyles = () => {
    return (
        <div style={divStyle}>hello, world</div>
    )
}
CSS Modules
  • 配置复杂:需要通过构建工具(如 Webpack)进行配置。​    
  • 样式依赖文件系统:样式存储在独立的文件中,可能影响开发体验。​    ​

styles.module.css

.bluAndPink {
    color: blue;
    backgroundColor: "pink";
}
import styles from "./styles.module.css"
const CSSModules = () => {
    return (
        <div>
             {/* CSS Modules */}
             <h1 className={styles.bluAndPink}>+</h1>
        </div>
    )
}
CSS-in-JS

styled-components库&Emotion

  • 性能开销:在运行时生成样式,可能会增加性能开销,特别是在大量组件中使用时。​    
  • 学习成本:需要学习特定的库和语法。​    
  • 打包体积:可能增加打包后的 JavaScript 体积。​    
  • SSR 支持较困难​    ​

安装依赖

npm install styled-components
import styled from 'styled-components';​ 
const Container = styled.div`​
    color: blue;​   
    background-color: lightgray;​ 
`;​ 
function StyledComponent() {​    
    return <Container>Hello, world!</Container>;​  
}
Tailwind CSS
  • 类名冗长:大量的类名可能导致 JSX 代码不易读。​    
  • 学习曲线:需要熟悉 Tailwind CSS 提供的类名和用法。​   
  • 灵活性受限:在一些复杂场景下,可能需要编写自定义样式。​

安装依赖

npm install tailwindcss​
npx tailwindcss init

配置: 在 tailwind.config.js 中配置,并在 index.css 中引入 Tailwind 样式。

function StyledComponent() {​ 
     return <div className="text-blue-500 bg-pink-200">Hello, world!</div>;​ 
}

10、React19

看不懂,回家再学

MATLAB主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性内容概要:本文主要介绍了一种在MATLAB环境下实现的主动噪声和振动控制算法,该算法针对较大的次级路径变化具有较强的鲁棒性。文中详细阐述了算法的设计原理与实现方法,重点解决了传统控制系统中因次级路径动态变化导致性能下降的问题。通过引入自适应机制和鲁棒控制策略,提升了系统在复杂环境下的稳定性和控制精度,适用于需要高精度噪声与振动抑制的实际工程场景。此外,文档还列举了多个MATLAB仿真实例及相关科研技术服务内容,涵盖信号处理、智能优化、机器学习等多个交叉领域。; 适合人群:具备一定MATLAB编程基础和控制系统理论知识的科研人员及工程技术人员,尤其适合从事噪声与振动控制、信号处理、自动化等相关领域的研究生和工程师。; 使用场景及目标:①应用于汽车、航空航天、精密仪器等对噪声和振动敏感的工业领域;②用于提升现有主动控制系统对参数变化的适应能力;③为相关科研项目提供算法验证与仿真平台支持; 阅读建议:建议读者结合提供的MATLAB代码进行仿真实验,深入理解算法在不同次级路径条件下的响应特性,并可通过调整控制参数进一步探究其鲁棒性边界。同时可参考文档中列出的相关技术案例拓展应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值