大白话React第七章深入学习 React 高级特性与优化阶段

大白话React第七章深入学习 React 高级特性与优化阶段

1. React Hooks 的深入学习

React Hooks 就像是给 React 开发者的一套超好用的工具包,让我们能更轻松地处理组件的状态和其他功能,而且不用像以前写类组件那么麻烦。

  • useEffect 钩子:它就像一个"监听器",可以监听组件的变化,比如数据的改变、组件的挂载和卸载等。然后在特定的情况下执行一些代码,比如从服务器获取数据或者清理一些副作用(像取消定时器)。
jsx 复制代码
import React, { useState, useEffect } from'react';

const DataFetchingComponent = () => {
    // 用 useState 管理数据状态
    const [data, setData] = useState([]);
    // 用 useEffect 来获取数据
    useEffect(() => {
        // 模拟从服务器获取数据
        const fetchData = async () => {
            const response = await fetch('https://jsonplaceholder.typicode.com/posts');
            const jsonData = await response.json();
            setData(jsonData);
        };
        fetchData();
    }, []);

    return (
        <div>
            <h2>从服务器获取的数据</h2>
            <ul>
                {data.map((item) => (
                    <li key={item.id}>{item.title}</li>
                ))}
            </ul>
        </div>
    );
};

export default DataFetchingComponent;

在这个例子里,useEffect 只在组件挂载时执行一次(因为依赖数组是空的 []),去获取服务器的数据并更新组件的状态。

  • useContext 钩子:它就像一个"全局广播器",能让你在组件树里共享数据,不用一层一层地把数据从父组件传到子组件。
jsx 复制代码
import React, { createContext, useContext, useState } from'react';

// 创建一个上下文
const ThemeContext = createContext();

const ParentComponent = () => {
    const [theme, setTheme] = useState('light');

    return (
        // 提供上下文值
        <ThemeContext.Provider value={{ theme, setTheme }}>
            <ChildComponent />
        </ThemeContext.Provider>
    );
};

const ChildComponent = () => {
    // 使用上下文
    const { theme, setTheme } = useContext(ThemeContext);

    return (
        <div>
            <p>当前主题: {theme}</p>
            <button onClick={() => setTheme(theme === 'light'? 'dark' : 'light')}>
                切换主题
            </button>
        </div>
    );
};

export default ParentComponent;

这里通过 createContext 创建了一个主题上下文,ParentComponent 提供了主题相关的数据和更新方法,ChildComponent 直接使用 useContext 获取这些数据并能进行主题切换。

2. 代码分割与懒加载

想象你的应用是一个大仓库,里面有很多货物(代码)。如果一次性把所有货物都拿出来,会很费时间。代码分割和懒加载就像是只在需要的时候才去拿特定的货物,能让应用加载得更快。

jsx 复制代码
import React, { Suspense } from'react';

// 懒加载组件
const LazyComponent = React.lazy(() => import('./LazyComponent'));

const App = () => {
    return (
        <div>
            <h1>代码分割与懒加载示例</h1>
            {/* Suspense 组件用来在组件加载时显示一个加载提示 */}
            <Suspense fallback={<div>加载中...</div>}>
                <LazyComponent />
            </Suspense>
        </div>
    );
};

export default App;

这里 React.lazyLazyComponent 实现了懒加载,Suspense 组件在 LazyComponent 还没加载好的时候显示一个"加载中..."的提示。

3. 错误边界处理

错误边界就像一个"安全卫士",当组件树里某个地方出了错误,它能拦截这个错误,不让应用崩溃,还能显示一个友好的错误提示给用户。

jsx 复制代码
class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props);
        this.state = { hasError: false };
    }

    componentDidCatch(error, errorInfo) {
        // 记录错误信息,可以发送到服务器等
        console.log('捕获到错误:', error, errorInfo);
        this.setState({ hasError: true });
    }

    render() {
        if (this.state.hasError) {
            return (
                <div>
                    <h2>哎呀,出了点问题!</h2>
                    <p>请稍后再试。</p>
                </div>
            );
        }
        return this.props.children;
    }
}

const App = () => {
    return (
        <ErrorBoundary>
            <div>
                {/* 这里假设 SomeComponent 可能会出错 */}
                <SomeComponent />
            </div>
        </ErrorBoundary>
    );
};

export default App;

ErrorBoundary 类组件通过 componentDidCatch 方法捕获子组件中的错误,并在出错时显示友好的错误提示页面。

4. 性能优化的进一步探索

除了之前学的一些性能优化方法,还可以进一步优化 React 应用。比如优化渲染性能,减少不必要的重渲染。可以使用 React.memo 来包裹函数组件,它就像一个"记忆大师",如果组件的 props 没有变化,就不会重新渲染组件。

jsx 复制代码
import React from'react';

const MyComponent = React.memo((props) => {
    console.log('组件渲染了');
    return <div>{props.message}</div>;
});

const App = () => {
    const [count, setCount] = React.useState(0);
    const message = '这是一个测试消息';

    return (
        <div>
            <button onClick={() => setCount(count + 1)}>点击增加计数</button>
            {/* 即使 count 变化,但 message 不变时,MyComponent 不会重新渲染 */}
            <MyComponent message={message} />
        </div>
    );
};

export default App;

在这个例子里,MyComponentReact.memo 包裹,当 count 变化但 message 不变时,MyComponent 不会重新渲染,从而提高了性能。

通过学习这些内容,你对 React 的理解会更加深入,能够开发出更高效、更健壮的 React 应用。

优化React应用性能的经验

以下是一些优化React应用性能的实践经验:

组件优化

  • 使用React.memo或PureComponent :对于函数组件,使用React.memo包裹可以浅比较组件的props,如果props没有变化,组件不会重新渲染。对于类组件,可以继承PureComponent,它会自动对props和state进行浅比较,减少不必要的渲染。
  • 合理使用useCallback和useMemouseCallback用于缓存函数,确保在组件重新渲染时,函数引用保持不变,避免子组件因函数引用变化而不必要地重新渲染。useMemo用于缓存计算结果,只有当依赖项变化时才重新计算,避免重复执行昂贵的计算。

渲染优化

  • 避免不必要的渲染 :在组件的render方法中,确保不要进行不必要的计算或操作。可以将一些计算放在useMemouseEffect中,根据依赖项的变化来执行。
  • 使用虚拟列表 :当渲染大量数据时,使用虚拟列表库,如react-virtualizedreact-window,只渲染可见区域的列表项,而不是一次性渲染所有项,能显著提高性能。
  • 优化列表渲染 :在渲染列表时,为列表项提供稳定的key值,React会利用key来高效地更新和复用列表项,避免不必要的重新渲染。

数据获取与状态管理

  • 数据缓存 :对于频繁获取且不经常变化的数据,可以在客户端进行缓存。可以使用localStoragesessionStorage或内存缓存库如lru-cache来存储数据,避免重复请求服务器。
  • 优化状态管理:避免在组件树中过度传递状态,如果多个组件需要共享状态,考虑使用状态管理库如Redux、Mobx或React Context来集中管理状态,减少组件之间的嵌套传递。

其他优化

  • 代码分割与懒加载 :利用React的代码分割功能,将应用分割成多个小块,按需加载。通过React.lazySuspense组件实现组件的懒加载,只有在需要时才加载相应的代码,提高初始加载速度。
  • 优化图片资源 :对图片进行压缩和优化,使用合适的图片格式,如WebP格式通常具有更好的压缩比和加载性能。可以使用图片加载库,如react-lazyload来实现图片的懒加载,避免一次性加载大量图片。
  • 减少内联样式:内联样式会增加渲染成本,尽量使用CSS类名来定义样式。如果需要动态样式,可以使用CSS-in-JS库,如Styled Components或Emotion,它们可以将样式进行优化和打包。

虚拟列表是如何工作的?

虚拟列表是一种在处理大量数据列表展示时提升性能的技术,以下是它的工作原理及相关示例:

工作原理

  • 只渲染可见区域:虚拟列表不会像普通列表那样一次性把所有数据对应的列表项都渲染出来,而是只渲染当前在屏幕上能看到的那部分列表项。比如你有一个包含1万条数据的列表,但手机屏幕一次只能显示10条,那虚拟列表就只渲染这10条,其他没在屏幕上的暂时不渲染,等用户滚动到相应位置时再去渲染。
  • 动态计算位置:虚拟列表会根据用户的滚动操作,实时计算哪些列表项应该出现在当前可见区域内。当用户滚动页面时,它会快速算出哪些新的列表项需要显示,哪些已经滚出屏幕的可以隐藏或卸载。
  • 复用列表项:虚拟列表会对列表项进行复用。比如一开始渲染了屏幕上可见的第1到第10条列表项,当用户向下滚动,第1条滚出屏幕,第11条需要显示时,它不会重新创建一个新的列表项来显示第11条数据,而是把刚才显示第1条数据的列表项拿过来,更新里面的内容为第11条数据的内容,然后显示出来,这样就节省了大量创建和销毁DOM元素的时间。

代码示例

以下是一个简单的使用react-window库实现虚拟列表的代码示例:

jsx 复制代码
import React from 'react';
import { FixedSizeList as List } from 'react-window';

// 列表项组件
const ListItem = ({ index, style }) => {
  return (
    <div style={style}>
      Item {index}
    </div>
  );
};

const App = () => {
  // 数据数组
  const data = Array.from({ length: 1000 }, (_, i) => i);

  // 渲染函数
  const renderItem = ({ index, style }) => {
    return <ListItem index={index} style={style} />;
  };

  return (
    <div>
      <h1>Virtual List Example</h1>
      {/* 虚拟列表组件 */}
      <List
        height={400}
        width={300}
        itemCount={data.length}
        itemSize={50}
        renderItem={renderItem}
      />
    </div>
  );
};

export default App;

在上述代码中,首先引入了react-window库中的FixedSizeList组件。然后定义了一个ListItem组件用于渲染单个列表项。在App组件中,创建了一个包含1000个元素的数据数组,通过renderItem函数来指定如何渲染每个列表项。最后,使用FixedSizeList组件创建虚拟列表,设置了列表的高度、宽度、列表项数量、每个列表项的高度以及渲染函数。

相关推荐
wrjwww11 分钟前
【Git学习笔记】Git常用命令
笔记·git·学习
学途路漫漫13 分钟前
怎么修改node_modules里的文件,怎么使用patch-package修改node_modules的文件,怎么修改第三方库原文件。
开发语言·javascript·ecmascript
蒜香拿铁38 分钟前
react-router的使用
前端·react.js
键盘敲没电1 小时前
【iOS】小蓝书学习(四)
学习·ios·cocoa
程序员黄同学2 小时前
请解释 React 中的 Hooks,何时使用 Hooks 更合适?
前端·javascript·react.js
朝阳392 小时前
Nuxt.js 3【详解】服务器 Server
服务器·javascript·nuxt.js
我要昵称干什么2 小时前
STM32学习——RTC实时时钟(BKP与RTC外设)
c语言·stm32·单片机·嵌入式硬件·学习·实时音视频
可可鸭~2 小时前
前端面试基础知识整理(一)
javascript·vue.js·学习·面试·elementui
爱上妖精的尾巴2 小时前
3-2 WPS JS宏 工作簿的打开与保存(模板批量另存为工作)学习笔记
javascript·笔记·学习·js·wps