单击按钮时如何防止我的页面呈现
How to prevent my Page render when I click on the button
我正在尝试优化我的 React 应用程序,在分析我的应用程序时,我发现当我单击“添加到购物车”页面时,我的整个页面都在重新呈现。任何人都可以帮助我,如何避免这种情况以及为什么会发生这种情况?
FYR,GitHub 回购:https://github.com/sandeep8080/shopping-cart-assignment
import { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import SideBar from "../../components/sideBar/SideBar";
import { getProductsData } from "../../redux/action/products";
import ProductCard from '../../components/productCard/ProductCard';
import './products.css';
import { getCategoryData } from "../../redux/action/category";
import Cart from "../cart/cart";
import Modal from '../../components/modal/Modal';
import { useHistory, useParams } from "react-router";
const ProductsPage = () => {
const dispatch = useDispatch();
const router = useHistory();
const { id } = useParams();
console.log(` product comp : ${id}`);
const productsData = useSelector(data => data.Products.products);
const sideBarData = useSelector(data => {
const listItems = data.Categories.CategoriesItems;
const activeListItems = listItems.filter(item => item.enabled === true);
return activeListItems;
});
const openCart = useSelector(state => state.CartDetails.isOpen);
const [fProductData, setFProductData] = useState([]);
useEffect(() => {
dispatch(getProductsData());
dispatch(getCategoryData());
}, []);
useEffect(() => {
if (id) {
filterDataByCategory(id);
} else {
setFProductData(productsData);
}
}, [productsData, id]);
// Function to filter out the data based on category
const filterDataByCategory = (id) => {
console.log("Filter data function called")
const filterData = productsData.filter(item => item.category === id);
setFProductData(filterData);
};
const handleClickProduct = useCallback((id) => {
filterDataByCategory(id);
router.push(`/products/${id}`);
}, [id]);
return (
<div className='product-main'>
<SideBar
sideBarData={sideBarData}
handleClickProduct={handleClickProduct}
/>
<div className='product-container'>
<div className='product-row'>
{
(fProductData).map((product) => {
return (
<div key={product.id} className='card-wrapper' >
<ProductCard key={product.id} {...product} />
</div>
)
})
}
</div>
</div>
{
openCart &&
<Modal>
<Cart />
</Modal>
}
</div >
)
};
export default ProductsPage;
// Product Card component
import './ProductCard.css';
import Button from '../button/Button';
import React from 'react';
import { useDispatch } from 'react-redux';
import { updateCart } from '../../redux/action/cart';
import priceFromatter from '../../lib/priceFromatter';
const ProductCard = ({ name, price, description, imageURL, id }) => {
const dispatch = useDispatch();
const handleClick = () => {
console.log('product clicked', id);
dispatch(updateCart(id, 'add'));
};
let imgURL = `../../${imageURL}`;
// imgURL = imgURL.replace(/([^:]\/)\/+/g, "");
// const image = React.lazy(() => import (`${imgURL}`));
// console.log(image);
return (
<article className='card-container'>
<h6 className='card-header'>
{name}
</h6>
<div className='content-container'>
<img
className='content-img'
// src={require(`${imgURL}`).default}
src={imageURL}
/>
<div className='content'>
<p className='content-desc'>{description}</p>
<div className='content-footer'>
<p>{priceFromatter(price)}</p>
<Button btnText='Add To Cart' handleClick={() => handleClick(id)} />
</div>
</div>
</div>
</article>
)
};
export default ProductCard;
import { callApi } from "../../lib/api";
import { actions } from '../actionContants/actionConstant';
export const toggleCart = (isToggle) => {
return {
type: actions.OPEN_CART,
payload: isToggle,
}
};
export const updateCart = (id, operation) => {
return async (dispatch, getState) => {
const productList = getState().Products.products;
const cartItems = getState().CartDetails.cartItems;
const currItem = productList.find(({ id: currentItemId }) => currentItemId === id);
const isItemInCart = cartItems.find(({ id }) => id === currItem.id);
let finalItem = [];
if (!isItemInCart) {
finalItem = [...cartItems, { ...currItem, count: 1 }]
} else {
finalItem = cartItems.map(item => {
if (item.id === currItem.id) {
operation === 'add' ? item.count = item.count + 1 : item.count = item.count - 1
}
return item;
}).filter(({ count }) => count)
}
try {
const result = await callApi.post('/addToCart', id);
result && dispatch({
type: actions.UPDATE_TO_CART,
payload: finalItem
})
} catch (error) {
console.log(error)
}
}
};
在 products.js
中更改以下代码块:
const sideBarData = useSelector(data => {
const listItems = data.Categories.CategoriesItems;
const activeListItems = listItems.filter(item => item.enabled === true);
return activeListItems;
});
至:
const sideBarData = useSelector(data => {
const listItems = data.Categories.CategoriesItems;
const activeListItems = listItems.filter(item => item.enabled === true);
return activeListItems;
}, shallowEqual);
useSelector
will force a component to re-render when the selector returns a new reference that is different than the previous reference (it uses the ===
operator).参考:https://react-redux.js.org/api/hooks#equality-comparisons-and-updates。当您过滤从商店返回的数组时,它始终是与商店中的对象引用不同的对象。
使用 shallowEqual
作为 equalityFn
到 useSelector()
可用于更改比较并防止不必要的 re-render <ProductsPage>
组件.
您是否尝试使用 e.preventDefault() 否则上面的答案可能有效
我正在尝试优化我的 React 应用程序,在分析我的应用程序时,我发现当我单击“添加到购物车”页面时,我的整个页面都在重新呈现。任何人都可以帮助我,如何避免这种情况以及为什么会发生这种情况?
FYR,GitHub 回购:https://github.com/sandeep8080/shopping-cart-assignment
import { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import SideBar from "../../components/sideBar/SideBar";
import { getProductsData } from "../../redux/action/products";
import ProductCard from '../../components/productCard/ProductCard';
import './products.css';
import { getCategoryData } from "../../redux/action/category";
import Cart from "../cart/cart";
import Modal from '../../components/modal/Modal';
import { useHistory, useParams } from "react-router";
const ProductsPage = () => {
const dispatch = useDispatch();
const router = useHistory();
const { id } = useParams();
console.log(` product comp : ${id}`);
const productsData = useSelector(data => data.Products.products);
const sideBarData = useSelector(data => {
const listItems = data.Categories.CategoriesItems;
const activeListItems = listItems.filter(item => item.enabled === true);
return activeListItems;
});
const openCart = useSelector(state => state.CartDetails.isOpen);
const [fProductData, setFProductData] = useState([]);
useEffect(() => {
dispatch(getProductsData());
dispatch(getCategoryData());
}, []);
useEffect(() => {
if (id) {
filterDataByCategory(id);
} else {
setFProductData(productsData);
}
}, [productsData, id]);
// Function to filter out the data based on category
const filterDataByCategory = (id) => {
console.log("Filter data function called")
const filterData = productsData.filter(item => item.category === id);
setFProductData(filterData);
};
const handleClickProduct = useCallback((id) => {
filterDataByCategory(id);
router.push(`/products/${id}`);
}, [id]);
return (
<div className='product-main'>
<SideBar
sideBarData={sideBarData}
handleClickProduct={handleClickProduct}
/>
<div className='product-container'>
<div className='product-row'>
{
(fProductData).map((product) => {
return (
<div key={product.id} className='card-wrapper' >
<ProductCard key={product.id} {...product} />
</div>
)
})
}
</div>
</div>
{
openCart &&
<Modal>
<Cart />
</Modal>
}
</div >
)
};
export default ProductsPage;
// Product Card component
import './ProductCard.css';
import Button from '../button/Button';
import React from 'react';
import { useDispatch } from 'react-redux';
import { updateCart } from '../../redux/action/cart';
import priceFromatter from '../../lib/priceFromatter';
const ProductCard = ({ name, price, description, imageURL, id }) => {
const dispatch = useDispatch();
const handleClick = () => {
console.log('product clicked', id);
dispatch(updateCart(id, 'add'));
};
let imgURL = `../../${imageURL}`;
// imgURL = imgURL.replace(/([^:]\/)\/+/g, "");
// const image = React.lazy(() => import (`${imgURL}`));
// console.log(image);
return (
<article className='card-container'>
<h6 className='card-header'>
{name}
</h6>
<div className='content-container'>
<img
className='content-img'
// src={require(`${imgURL}`).default}
src={imageURL}
/>
<div className='content'>
<p className='content-desc'>{description}</p>
<div className='content-footer'>
<p>{priceFromatter(price)}</p>
<Button btnText='Add To Cart' handleClick={() => handleClick(id)} />
</div>
</div>
</div>
</article>
)
};
export default ProductCard;
import { callApi } from "../../lib/api";
import { actions } from '../actionContants/actionConstant';
export const toggleCart = (isToggle) => {
return {
type: actions.OPEN_CART,
payload: isToggle,
}
};
export const updateCart = (id, operation) => {
return async (dispatch, getState) => {
const productList = getState().Products.products;
const cartItems = getState().CartDetails.cartItems;
const currItem = productList.find(({ id: currentItemId }) => currentItemId === id);
const isItemInCart = cartItems.find(({ id }) => id === currItem.id);
let finalItem = [];
if (!isItemInCart) {
finalItem = [...cartItems, { ...currItem, count: 1 }]
} else {
finalItem = cartItems.map(item => {
if (item.id === currItem.id) {
operation === 'add' ? item.count = item.count + 1 : item.count = item.count - 1
}
return item;
}).filter(({ count }) => count)
}
try {
const result = await callApi.post('/addToCart', id);
result && dispatch({
type: actions.UPDATE_TO_CART,
payload: finalItem
})
} catch (error) {
console.log(error)
}
}
};
在 products.js
中更改以下代码块:
const sideBarData = useSelector(data => {
const listItems = data.Categories.CategoriesItems;
const activeListItems = listItems.filter(item => item.enabled === true);
return activeListItems;
});
至:
const sideBarData = useSelector(data => {
const listItems = data.Categories.CategoriesItems;
const activeListItems = listItems.filter(item => item.enabled === true);
return activeListItems;
}, shallowEqual);
useSelector
will force a component to re-render when the selector returns a new reference that is different than the previous reference (it uses the ===
operator).参考:https://react-redux.js.org/api/hooks#equality-comparisons-and-updates。当您过滤从商店返回的数组时,它始终是与商店中的对象引用不同的对象。
使用 shallowEqual
作为 equalityFn
到 useSelector()
可用于更改比较并防止不必要的 re-render <ProductsPage>
组件.
您是否尝试使用 e.preventDefault() 否则上面的答案可能有效