MST

星途 面试题库

面试题:Qwik复杂场景下Props与State的优化搭配

假设你正在开发一个Qwik电商产品展示组件,该组件需要接收来自父组件的商品数据Props(如商品列表、价格等),同时自身维护一些State(如商品是否被选中、购物车数量等)。请阐述在性能优化方面,如何合理地更新Props和State,避免不必要的重渲染,并且说明在处理大量商品数据时的策略。
23.0万 热度难度
前端开发Qwik

知识考点

AI 面试

面试题答案

一键面试

更新Props和State避免不必要重渲染

  1. 使用React.memo
    • 对于展示商品的子组件,用React.memo包裹。React.memo是一个高阶组件,它会对组件的Props进行浅比较。如果Props没有变化,组件就不会重新渲染。例如:
    const ProductItem = React.memo(({ product }) => {
      return (
        <div>
          <p>{product.name}</p>
          <p>{product.price}</p>
        </div>
      );
    });
    
  2. 浅比较Props和State
    • shouldComponentUpdate生命周期方法(在类组件中)或使用自定义Hook来实现类似功能(在函数组件中)。对于商品是否被选中、购物车数量等State,在更新前进行浅比较。例如,在类组件中:
    class ProductList extends React.Component {
      shouldComponentUpdate(nextProps, nextState) {
        // 浅比较商品列表Props
        if (!shallowEqual(this.props.products, nextProps.products)) {
          return true;
        }
        // 浅比较购物车数量State
        if (this.state.cartCount!== nextState.cartCount) {
          return true;
        }
        return false;
      }
      //...其他组件逻辑
    }
    
    • 在函数组件中可以使用useCallbackuseMemo。例如,当有一个函数依赖于State或Props时:
    const ProductList = ({ products }) => {
      const [cartCount, setCartCount] = useState(0);
      const handleAddToCart = useCallback(() => {
        setCartCount(cartCount + 1);
      }, [cartCount]);
      // 这里products依赖数组可以省略,因为如果products变化,组件会重新渲染,handleAddToCart会重新生成
      const memoizedProducts = useMemo(() => products, [products]);
      //...渲染逻辑
    };
    
  3. 批量更新
    • 在React中,当多个State更新在同一事件循环内发生时,React会批量更新。但在某些情况下(如原生DOM事件处理函数内),React不会自动批量更新。这时可以使用unstable_batchedUpdates(在React 18之前)或flushSync(React 18及之后)。例如:
    import React, { useState, useEffect } from'react';
    import { flushSync } from'react-dom';
    
    const ProductList = () => {
      const [cartCount, setCartCount] = useState(0);
      const [selectedProduct, setSelectedProduct] = useState(null);
    
      const handleClick = () => {
        flushSync(() => {
          setCartCount(cartCount + 1);
          setSelectedProduct({ id: 1, name: 'Sample Product' });
        });
      };
    
      return (
        <div>
          <button onClick={handleClick}>Add to Cart</button>
          <p>Cart Count: {cartCount}</p>
          {selectedProduct && <p>Selected Product: {selectedProduct.name}</p>}
        </div>
      );
    };
    

处理大量商品数据时的策略

  1. 虚拟化列表
    • 使用像react - virtualizedreact - window这样的库。这些库只渲染当前可见的商品项,而不是渲染所有商品。例如,使用react - virtualizedList组件:
    import React from'react';
    import { List } from'react - virtualized';
    
    const products = Array.from({ length: 1000 }, (_, i) => ({ id: i, name: `Product ${i}`, price: i * 10 }));
    
    const rowRenderer = ({ index, key, style }) => {
      const product = products[index];
      return (
        <div key={key} style={style}>
          <p>{product.name}</p>
          <p>{product.price}</p>
        </div>
      );
    };
    
    const ProductList = () => {
      return (
        <List
          height={400}
          rowCount={products.length}
          rowHeight={50}
          rowRenderer={rowRenderer}
          width={300}
        />
      );
    };
    
  2. 分页
    • 将商品数据分成多个页面,每次只请求和渲染当前页面的数据。例如,在后端接口中添加分页参数:
    const pageSize = 10;
    const [currentPage, setCurrentPage] = useState(1);
    const startIndex = (currentPage - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    const currentProducts = products.slice(startIndex, endIndex);
    
    return (
      <div>
        {currentProducts.map(product => (
          <div key={product.id}>
            <p>{product.name}</p>
            <p>{product.price}</p>
          </div>
        ))}
        <button onClick={() => setCurrentPage(currentPage - 1)} disabled={currentPage === 1}>Previous</button>
        <button onClick={() => setCurrentPage(currentPage + 1)} disabled={endIndex >= products.length}>Next</button>
      </div>
    );
    
  3. 数据缓存
    • 对于已经获取过的商品数据进行缓存。可以使用localStorage(适用于较小数据量且不敏感数据)或在内存中进行缓存(例如使用一个对象来存储已请求的数据)。例如:
    const productCache = {};
    const getProducts = async () => {
      if (productCache['all']) {
        return productCache['all'];
      }
      const response = await fetch('/api/products');
      const data = await response.json();
      productCache['all'] = data;
      return data;
    };