首页 > 其他分享 >React性能优化实战:从理论到落地的最佳实践

React性能优化实战:从理论到落地的最佳实践

时间:2024-12-20 21:56:10浏览次数:5  
标签:实战 return 落地 React products filters const 优化

"这个列表页怎么这么卡?"产品经理皱着眉头看着我。作为一个接手海外电商项目的前端开发者,我深知性能问题的重要性。特别是在东南亚市场,很多用户使用的是中低端手机,网络条件也不太理想。

最近一个月,我带领团队对整个React应用进行了一次全面的性能优化,不仅解决了性能问题,还总结出了一套可复用的优化方案。今天就来分享这个过程中的实战经验。

性能问题分析

首先,我们用 Chrome DevTools 和 React DevTools 对应用进行了全面的性能分析。问题主要集中在这几个方面:

  1. 列表页面首次加载需要3秒以上
  2. 切换tab时明显卡顿
  3. 输入搜索关键词时,界面响应延迟
  4. 滚动大量商品时,帧率明显下降

通过 Performance 面板的记录,我们发现主要是这些原因导致:

// 示例:性能问题的代码模式
const ProductList = () => {
  const [products, setProducts] = useState([])
  const [filters, setFilters] = useState({})

  // 问题1:每次渲染都会重新创建函数
  const handleFilter = (newFilters) => {
    setFilters(newFilters)
  }

  // 问题2:没有做数据缓存
  const filteredProducts = products.filter(product => {
    return Object.entries(filters).every(([key, value]) => 
      product[key] === value
    )
  })

  // 问题3:子组件没有做优化
  return (
    <div>
      {filteredProducts.map(product => (
        <ProductCard key={product.id} {...product} />
      ))}
    </div>
  )
}

优化方案实施

1. 组件优化

首先是最基础的组件优化。我们使用 React.memo 和 useMemo 来避免不必要的重渲染:

// 优化后的 ProductCard 组件
const ProductCard = React.memo(({ id, name, price, image }) => {
  // 只有当props真正变化时才重新渲染
  return (
    <div className="product-card">
      <img src={image} alt={name} loading="lazy" />
      <h3>{name}</h3>
      <p>{formatPrice(price)}</p>
    </div>
  )
}, (prevProps, nextProps) => {
  // 自定义比较函数,只比较关键属性
  return (
    prevProps.id === nextProps.id &&
    prevProps.price === nextProps.price
  )
})

// 优化列表渲染
const ProductList = () => {
  const [products, setProducts] = useState([])
  const [filters, setFilters] = useState({})

  // 缓存过滤函数
  const handleFilter = useCallback((newFilters) => {
    setFilters(newFilters)
  }, [])

  // 缓存过滤结果
  const filteredProducts = useMemo(() => {
    return products.filter(product => {
      return Object.entries(filters).every(([key, value]) => 
        product[key] === value
      )
    })
  }, [products, filters])

  return (
    <div>
      <FilterPanel onFilter={handleFilter} />
      <VirtualizedList
        items={filteredProducts}
        renderItem={(product) => (
          <ProductCard key={product.id} {...product} />
        )}
      />
    </div>
  )
}

2. 数据处理优化

对于数据处理,我们采用了几个关键的优化策略:

// 1. 使用规范化的数据结构
interface NormalizedState {
  products: {
    byId: Record<string, Product>;
    allIds: string[];
  };
  categories: {
    byId: Record<string, Category>;
    allIds: string[];
  };
}

// 2. 实现高效的数据查询
const useProductsQuery = (filters: Filters) => {
  const queryClient = useQueryClient()

  return useQuery({
    queryKey: ['products', filters],
    queryFn: () => fetchProducts(filters),
    // 实现数据预加载
    placeholderData: () => {
      // 使用已有数据作为占位
      return queryClient.getQueryData(['products'])
    },
    // 智能缓存策略
    staleTime: 5 * 60 * 1000, // 5分钟
    cacheTime: 30 * 60 * 1000 // 30分钟
  })
}

// 3. 优化状态更新
const useProductsStore = create((set) => ({
  products: [],
  setProducts: (newProducts) => {
    set((state) => ({
      products: produce(state.products, (draft) => {
        // 使用 Immer 进行高效的不可变更新
        draft.push(...newProducts)
      })
    }))
  }
}))

3. 渲染优化

为了解决长列表渲染的问题,我们实现了虚拟滚动:

const VirtualizedList = ({ items, renderItem, itemHeight = 200 }) => {
  const containerRef = useRef<HTMLDivElement>(null)
  const [visibleRange, setVisibleRange] = useState({ start: 0, end: 10 })

  const onScroll = useCallback(() => {
    if (!containerRef.current) return

    const { scrollTop, clientHeight } = containerRef.current
    const start = Math.floor(scrollTop / itemHeight)
    const end = Math.min(
      start + Math.ceil(clientHeight / itemHeight),
      items.length
    )

    setVisibleRange({ start, end })
  }, [itemHeight, items.length])

  // 只渲染可见区域的项目
  const visibleItems = useMemo(() => {
    return items.slice(visibleRange.start, visibleRange.end)
  }, [items, visibleRange])

  return (
    <div 
      ref={containerRef}
      style={{ height: '100vh', overflow: 'auto' }}
      onScroll={onScroll}
    >
      <div style={{ height: items.length * itemHeight }}>
        <div style={{ 
          transform: `translateY(${visibleRange.start * itemHeight}px)`
        }}>
          {visibleItems.map(renderItem)}
        </div>
      </div>
    </div>
  )
}

4. 网络优化

最后,我们还对网络请求进行了优化:

// 1. 实现请求去重和缓存
const requestCache = new Map()

const fetchWithCache = async (url: string, options = {}) => {
  const cacheKey = `${url}-${JSON.stringify(options)}`

  if (requestCache.has(cacheKey)) {
    return requestCache.get(cacheKey)
  }

  const promise = fetch(url, options).then(res => res.json())
  requestCache.set(cacheKey, promise)

  try {
    const result = await promise
    return result
  } finally {
    // 5分钟后清除缓存
    setTimeout(() => {
      requestCache.delete(cacheKey)
    }, 5 * 60 * 1000)
  }
}

// 2. 实现数据预加载
const prefetchNextPage = (currentPage: number) => {
  const nextPage = currentPage + 1

  // 预加载下一页数据
  fetchWithCache(`/api/products?page=${nextPage}`, {
    priority: 'low' // 使用低优先级请求
  })
}

优化效果

经过这一系列优化,我们取得了显著的效果:

  1. 首屏加载时间从3秒减少到1.2秒
  2. 列表滚动帧率稳定在60fps
  3. 搜索响应时间从500ms减少到100ms
  4. 内存占用减少40%

最让我欣慰的是收到用户的反馈:"现在浏览商品太流畅了!"这让之前的努力都值得了。

经验总结

React性能优化不是一蹴而就的,需要从多个层面系统地思考和实施:

  1. 组件层面:合理使用 memo、useMemo、useCallback
  2. 数据层面:规范化数据结构,实现高效的状态管理
  3. 渲染层面:采用虚拟滚动,延迟加载
  4. 网络层面:请求优化,数据预加载

写在最后

性能优化是一个持续的过程,不是一次性的工作。通过这次优化,我不仅解决了具体的性能问题,更重要的是建立了一套可持续的性能优化方法论。

如果你也在做React应用的性能优化,欢迎在评论区分享你的经验,让我们一起进步!

如果觉得这篇文章对你有帮助,别忘了点个赞

标签:实战,return,落地,React,products,filters,const,优化
From: https://blog.csdn.net/ChengFengTech/article/details/144599587

相关文章

  • 腾讯云云开发 Copilot 深度探索与实战分享
    个人主页:♡喜欢做梦 欢迎  ......
  • Python网络爬虫技术详解与实战案例
    Python网络爬虫技术详解与实战案例引言网络爬虫(WebCrawler)是一种自动化程序,用于在互联网上收集数据。通过向网页发送HTTP请求,获取网页数据,然后提取和分析网页内容,网络爬虫能够实现数据收集、信息提取和数据分析等多种应用场景。Python作为一种功能强大且易于学习的编程语......
  • C++中的智能指针:深入解析与实战案例
    C++中的智能指针:深入解析与实战案例在C++编程中,内存管理一直是一个核心且复杂的话题。手动管理内存不仅繁琐,而且容易出错,如内存泄漏、野指针等问题时常困扰着开发者。为了缓解这些问题,C++11引入了智能指针(SmartPointers),它们通过自动管理内存生命周期,极大地减少了内存管理......
  • Agent智能体,打响中国大模型落地产业第一枪
    与大模型不同,Agent就像是一个“标准答案”,直接摆在企业面前,就连使用说明书和企业最看重的投入回报比都计算好了。前排提示,文末有大模型AGI-CSDN独家资料包哦!“今年,我们是针对具体的场景构建大模型,等到明年会进行更深一步的探索。目前我们正在和云服务伙伴讨论构建数字员工......
  • Java项目实战之基于 Spring Boot+MyBatisPlus+MySQL+JSP的毕业设计综合信息管理系统
    1.引言1.1项目背景毕业设计是高等教育中的重要环节,为了提高毕业设计管理的效率和质量,实现信息化管理,特开发本毕业设计综合信息管理系统。该系统涵盖了毕业设计过程中的各个环节,包括管理员信息管理、院系专业管理、学生信息管理、教师信息管理、论文题目审核、选题信息管理、历......
  • 【项目实战】ISIC 数据集上的实验揭秘:UNet + SENet、Spatial Attention 和 CBAM 的最
    “听说有人用UNet找到了CT里的小肿块,也有人用它画了比自己还帅的自拍照。于是我想,UNet这么万能,是不是还能帮我找到我丢的袜子?”别急,这篇文章不会帮你找袜子,但绝对会让你搞懂UNet的精髓!从医学影像到图像分割,UNet堪称卷积神经网络界的全能选手。如果你也是对它一知半解的“......
  • 【机器学习与数据挖掘实战】案例05:基于决策树、梯度提升和XGBoost分类算法的O2O优惠券
    【作者主页】FrancekChen【专栏介绍】⌈⌈⌈机器学习与数据挖掘实战案例⌋......
  • DuckDB:JSON数据探索性分析实战教程
    简单来说,EDA通常指的是数据集的任何初始处理。通常,这些是较小的数据集,是较大数据集的子集,但你也可以使用大数据执行EDA。在本文中,你将扮演SecOps分析师的角色,对EDR(EndpointDetectionandResponse:端点检测和响应)数据的快照执行EDA,这些数据可能来自主流工具。测试数据......
  • Java项目实战之基于springboot+vue+mysql+jpa+redis的企业网站搭建设计文档设计与实现
    一、引言1.1项目背景随着互联网的飞速发展,企业网站已成为企业展示形象、推广产品和服务、与客户沟通的重要窗口。为了提升企业的竞争力,需要构建一个功能完善、用户体验良好的企业网站。1.2项目目标本项目旨在打造一个专业、高效、易用的企业网站,满足企业在品牌展示、产品推......
  • RK3566触摸驱动产品实战 配置设备树 I2C驱动框架(附源码)
    引言:相信大家在学完相关驱动框架很少真正的运用在实际的产品案例中,对设备树以及驱动框架还是非常的陌生,其次就是在编写相关驱动还有完成项目任务时的一些思路的引导,这些都是需要补足的,接下来,我们将之前理论知识与此文章内容结合,真正的将理论运用在实际案例中,形成自己的知识框......