javascript - getServerSideProps 提供数据但不重新渲染
问题描述
我的方法可能是针对 SSR 的,但我想要实现的是,在用户访问时渲染所有产品/products
,并且通过简单的products.map(...)
. 我还有一个类别过滤器,我确实为该复选框设置了一个 onClick,它基本上路由到/products?category=${categoryName}
它设置 url,控制台记录的过滤产品是正确的,但不更新第一个渲染的产品。
这是我的getServerSideProps
;
export const getServerSideProps = async (context) => {
const { db } = await connectToDatabase();
const getCategoriesFromDB = await db
.collection('categories')
.find({})
.toArray();
const getCategories = await JSON.parse(JSON.stringify(getCategoriesFromDB));
if (
!(
Object.keys(context.query).length === 0 &&
context.query.constructor === Object
)
) {
console.log('if fired!');
console.log(context.query);
const category = context.query.category;
const getFilteredProducts = await db
.collection('products')
.find({
category: category,
})
.toArray();
const getProducts = await JSON.parse(JSON.stringify(getFilteredProducts));
console.log(getProducts);
return {
props: {
getCategories,
getProducts,
},
};
} else {
console.log('else fired!');
const getProductsFromDB = await db
.collection('products')
.find({})
.toArray();
const getProducts = await JSON.parse(JSON.stringify(getProductsFromDB));
return {
props: {
getCategories,
getProducts,
},
};
}
};
这是一些状态和useEffect;
const Products = ({ getCategories, getProducts }) => {
const classes = useStyles();
const [products, setProducts] = useState(getProducts);
const [categories, setCategories] = useState([]);
const router = useRouter();
console.log(products);
console.log(categories);
useEffect(() => {
if (categories.length === 0) {
setProducts(getProducts);
}
}, [categories, products]);
const addToFilter = async (e) => {
const categoryName = e.currentTarget.dataset.category;
if (categories.length === 0) {
setCategories([...categories, categoryName]);
}
router.push(
`${process.env.NEXT_PUBLIC_URL}/products?category=${categoryName}`
);
};
这是我渲染产品的 div;
{products.map((product) => (
<Grid
item
md={3}
xs={6}
className={classes.productCardWrapper}
key={product._id}
>
<div className={classes.productCard}>
<div className={classes.productImageWrapper}>
<Image
src={product.image[0].secure_url}
alt={`${process.env.NEXT_PUBLIC_URL} ${product.name}`}
height={300}
width={450}
/>
</div>
<Typography className={classes.productCardTypo}>
{product.name}
</Typography>
<Typography variant='h6' className={classes.productCardTypo}>
€{product.price}
</Typography>{' '}
我已经习惯了 NextJS,所以我不确定我的方法是否不正确。
正如我所说,我在 vscode 终端上获得了过滤后的产品,但浏览器仍然记录了旧产品控制台。
解决方案
为了更方便,我也从后端过滤产品,不再是前端。但我仍然使用getServerSideProps
; 这是代码
export const getServerSideProps = async (context) => {
const { db } = await connectToDatabase();
const getCategoriesFromDB = await db
.collection('categories')
.find({})
.toArray();
const getCategories = await JSON.parse(JSON.stringify(getCategoriesFromDB));
if (
!(
Object.keys(context.query).length === 0 &&
context.query.constructor === Object
)
) {
const category = context.query.category;
if (typeof context.query.category === 'string') {
const getFilteredProducts = await db
.collection('products')
.find({
category: category,
})
.toArray();
const getProducts = await JSON.parse(JSON.stringify(getFilteredProducts));
return {
props: {
getCategories,
getProducts,
},
};
} else if (
typeof context.query.category === 'object' &&
context.query.category.length > 1
) {
let orArray = [];
for (let i = 0; i < context.query.category.length; i++) {
let categoryItem = {};
let element = context.query.category[i];
categoryItem = { category: element };
orArray.push(categoryItem);
}
const filteredProducts = await db
.collection('products')
.aggregate([
{
$match: {
$or: orArray,
},
},
])
.toArray();
const getProducts = await JSON.parse(JSON.stringify(filteredProducts));
return {
props: {
getCategories,
getProducts,
},
};
}
} else {
const getProductsFromDB = await db
.collection('products')
.find({})
.toArray();
const getProducts = await JSON.parse(JSON.stringify(getProductsFromDB));
return {
props: {
getCategories,
getProducts,
},
};
}
};
我在那里渲染产品;
<Grid
item
container
md={10}
spacing={3}
className={classes.productsGridContainer}
>
{getProducts.map((product) => (
<Grid
item
md={3}
xs={6}
className={classes.productCardWrapper}
key={product._id}
>
<div className={classes.productCard}>
<Link
href={`${
process.env.NEXT_PUBLIC_URL
}/products/${product.name.toLowerCase().replace(' ', '-')}`}
>
<a className={classes.productLink}>
<div className={classes.productImageWrapper}>
<Image
src={product.image[0].secure_url}
alt={`${process.env.NEXT_PUBLIC_URL} ${product.name}`}
height={350}
width={400}
/>
</div>
<Typography
className={classes.productCardTypo}
style={{ textAlign: 'center' }}
>
{product.name}
</Typography>
</a>
</Link>
<Typography
variant='h6'
style={{ color: '#5652de' }}
className={classes.productCardTypo2}
>
€{product.price}
</Typography>
<div className={classes.productCardBtn}>
<Button
style={{
backgroundColor: `${!product.active && '#f6f6f6'}`,
}}
fullWidth
color='primary'
variant='contained'
disableRipple
disableFocusRipple
disableElevation
disableTouchRipple
disabled={product.active ? false : true}
>
{product.active ? (
<>
<AddShoppingCartIcon fontSize='small' />
<span className={classes.productCardBtnWrapper}>
Add to Cart
</span>
</>
) : (
<>
<RemoveShoppingCartIcon fontSize='small' />
<span className={classes.productCardBtnWrapper}>
Out of Stock
</span>
</>
)}
</Button>
</div>
</div>
</Grid>
))}
</Grid>