簡體   English   中英

你能控制基於 state 變化的功能性反應組件的重新渲染嗎?

[英]Can you control the re-renders of a functional react component based on state change?

我有一個基本的電子商務應用程序供練習。 有一個名為“Shop”的功能組件有兩種狀態:

[products, setProducts] = useState([10ProductObjects])
and [cart, setCart] = useState([])

在第一個渲染周期中,加載了 10 個產品,每個Product組件都有一個“添加到購物車”按鈕,用於將產品添加到購物車數組。 當我單擊按鈕時,會填充購物車數組並顯示其長度。 但是,這樣做會再次重新渲染這 10 個產品,即使它們沒有任何更改。

現在我看到了,因為其中一個狀態發生了變化,即購物車數組,整個Shop組件再次呈現。 依次渲染其子組件,包括未更改的子組件。

我嘗試使用React.memo但這無濟於事,因為“商店”上沒有更改任何道具,而是 state 正在更改。 我還使用了useMemo鈎子,它有一些有趣的結果。

使用 products 數組作為依賴解決了額外的重新渲染問題,但新產品不再添加到購物車中。 使用這兩個[products, cart]作為依賴項是可行的,但會帶回原來的問題。

我知道可以使用shouldComponentUpdate來完成,但我需要功能組件中的那種靈活性。

注意:這是我的第一個問題,我很樂意聽取任何反饋。

import React, { useState, useMemo } from 'react';
import fakeData from '../../fakeData';
import Product from '../Product/Product';

const Shop = () => {
console.log('[Shop.js] rendered')
const first10 = fakeData.slice(0, 10);
const [products, setProducts] = useState(first10);
const [cart, setCart] = useState([]);


const addProductHandler = (product) => {
    console.log(cart, product);
    const newCart = [...cart, product];
    console.log(newCart); 
    setCart(newCart);
    
}
let productsOnScreen = useMemo(() => {
    return products.map( prod => {
        return  <Product product={prod} addProductHandler={addProductHandler} />
    });
}, [products])

 
return (
    <div className="shop-container">
        <div className="product-container">
            {productsOnScreen}
        </div>
        <div className="cart-container">
            <h3>this is cart</h3>
            <h5>Order Summary: {cart.length}</h5>
    </div>
    </div>
);
};

export default Shop;

使用addProductHandlerReact.useCallback以便對它的引用在渲染之間不會改變:

const addProductHandler = React.useCallback((product) => {
    setCart(oldCart => {
        return [...oldCart, product];
    });
}, [setCart]);

然后,用React.memo <Product> 您沒有發布該組件的代碼,但它看起來像這樣:

export const Product = React.memo((props) => {
  // normal functional component stuff

  return <>product component or whatever</>;
});

這些都是組件避免不必要的重新渲染所必需的。 為什么?

  1. React.useCallback允許通過引用進行比較以在渲染之間為回調 function 工作。 如果您像當前一樣在每次渲染時聲明回調 function,這將不起作用。
  2. React.memo包裝了一個組件,使其能夠根據其 props 的淺層比較來渲染或渲染。 默認情況下,React 組件不會這樣做,您必須使用React.memo顯式啟用它。

正如文檔提到的:

此方法僅作為性能優化存在。 不要依賴它來“阻止”渲染,因為這可能會導致錯誤。

換句話說,你應該只在遇到速度下降的情況下將其用作性能優化,而不是因為任何其他原因阻止渲染,並且只有在你實際遇到性能問題時才應該使用它。

如果這不起作用,則您的<Product>道具之一可能仍在渲染之間發生變化(在按引用進行淺層比較的情況下)。 繼續玩和記憶道具,直到你弄清楚哪些在渲染之間發生了變化。 測試這一點的一種方法是在<Product>內部使用一個簡單的React.useEffect (僅用於調試目的),它會在道具發生更改時提醒您:

React.useEffect(() => {
    console.log('product prop changed');
}, [product]);

React.useEffect(() => {
    console.log('addProductHandler prop changed');
}, [addProductHandler]);

// etc...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM