Mes données bestSellerDummy ne changent pas, donc j'aimerais éviter que le même enfant Product ne soit renvoyé si le parent effectue un nouveau rendu. J'ai essayé d'utiliser useMemo dans le parent et React.memo dans l'enfant mais pas de chance, il affiche toujours le journal 'Rendering Product component ..' à chaque fois que les parents rediffusent. Qu'est-ce que j'oublie ici? S'il vous plaît des conseils.
Remarque: Parent devrait être renvoyé chaque fois que j'appelle la fonction addToCart (de CartContext) dans un composant Product.
J'utilise CartContext, peut-être lié à cela, je ne suis pas sûr. Voici le bac à sable: https://codesandbox.io/s/dazzling-moore-po1c6?file=/src/App.js
Accueil.tsx
const Product: FunctionComponent<IProductProps> = ( productProps, ) => { ... console.log('Rendering Product component..'); ... } export default React.memo(Product);
Product.tsx
const [bestSellerDummy] = useState( [...new Array(5)].map((item, key) => ({ id: key, imageUri:'https://1.jpg', name: 'My Dummy 1', price: 25, })), ); const bestSellers = useMemo(() => { return bestSellerDummy.map((productDummy, key) => { return ( <Product key={key} product={productDummy} /> ); }); }, [bestSellerDummy]); return ( ... {bestSellers} ... )
=== MODIFIER: MA VERSION DE REPONSE ===
Finalement! Après avoir joué avec useCallback
, useMemo
, plugin fast-memoize
.. Ce qui me convient le mieux, c'est d'utiliser useReducer
en contexte combiné avec l'enveloppement du composant coûteux avec React.memo
. Je pense que c'est le moyen le plus propre et le plus élégant d'optimiser les composants enfants. Le sandbox de travail est ici: https://codesandbox.io/s/eloquent-albattani-8x7h9?file=/src/App.js
3 Réponses :
Essayez de cette façon
const [bestSellerDummy, setBestSellerDummy] = useState([]); // default empty // get data from `useCallback` const sellerData = React.useCallback( () => { return [...new Array(5)].map((item, key) => ({ id: key, imageUri:'https://1.jpg', name: 'My Dummy 1', price: 25, })) }, [] ); useEffect( () => { setBestSellerDummy( sellerData() ); // set data when screen rendered from `useCallback` }, []) const bestSellers = useMemo(() => { .... }, [bestSellerDummy]); return ( ... {bestSellers} ... )
@Jeaf essayez de supprimer ...
de [...new Array(5)]
Enveloppez BestSellers
composant React.memo
avec React.memo
. N'utilisez pas useMemo
pour éviter les mises à jour inutiles des composants car cela peut provoquer des bogues. Il est utilisé pour calculer des valeurs coûteuses.
Source: https://reactjs.org/docs/hooks-reference.html#usememo
Je pense que c'est également correct! J'ai combiné avec la réponse de dongnhan comme version de la réponse (fournie dans la question modifiée). Je l'apprécie vraiment, merci.
Puisque vous utilisez useContext
, votre composant sera toujours useContext
.
Lorsque le <MyContext.Provider> le plus proche au-dessus du composant est mis à jour, ce Hook déclenchera un rerender avec la dernière valeur de contexte transmise à ce fournisseur MyContext. Même si un ancêtre utilise React.memo ou shouldComponentUpdate, un rerender se produira toujours à partir du composant lui-même en utilisant useContext.
Référence: https://reactjs.org/docs/hooks-reference.html#usecontext
J'essayais de refactoriser votre code en utilisant la 2ème stratégie pointée de la documentation: https://github.com/facebook/react/issues/15156#issuecomment-474590693 .
Cependant, je me suis vite rendu compte que la fonction addToCart
avait cartItems
comme dépendance, donc chaque fois que cartItems
change, addToCart
change et il est en quelque sorte impossible d'éviter les rendus puisque chaque composant Product
utilise la fonction addToCart
.
Cela m'amène à utiliser useReducer
car React garantit que son dispatch
est stable et ne changera pas lors des re-rendus.
Voici donc le Codesandbox de travail: https://codesandbox.io/s/red-feather-dc7x6?file=/src/App.js:786-797
Ahh d'accord. Merci, Dongnhan! C'est tellement soigné et fonctionne comme un charme 👍✨
Btw, lorsque nous avons besoin d'une quantité dynamique comme paramètre onPress, cela interrompt la mémorisation et le problème revient: codesandbox.io/s/eloquent-albattani-8x7h9?file=/src/App.js . Une idée pour résoudre ce problème sans le plugin 'fast-memoize'? ( stackoverflow.com/questions/61255053/… )
@JeafGilbert, changez cette ligne en ceci onAddToCart={handleAddToCart}
. En utilisant onAddToCart={(addQty)=>{handleAddToCart(addQty)}
, vous créez un nouveau gestionnaire à chaque fois, ce qui provoque les re-rendus.
Résolu! codesandbox.io/s/eloquent-albattani-8x7h9?file=/src/App.js
Qu'est-ce qui cause le nouveau rendu de l'élément parent? Pourriez-vous fournir un exemple reproductible minimal via Codesandbox?
On s'attend à ce que @dongnhan Parent soit renvoyé chaque fois que j'appelle la fonction addToCart (de CartContext) dans un composant Product.
Vous pouvez également passer un deuxième rappel pour comparer le moment du
render
dans React.memo . Ce serait génial si vous ajoutez un bac à sable. Sinon, c'est difficile à direOn y va: codesandbox.io/s/dazzling-moore-po1c6?file=/src/App.js