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,};
  }
};

这里是一些状态和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 终端上获取了过滤后的产品,但浏览器仍然记录了旧产品控制台。

lorndrifter 回答:getServerSideProps 提供数据但不重新渲染

为了更方便,我还从后端过滤产品,不再是前端。但我仍然使用 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,};
    }
  } else {
    const getProductsFromDB = await db
      .collection('products')
      .find({})
      .toArray();
    const getProducts = await JSON.parse(JSON.stringify(getProductsFromDB));
    return {
      props: {
        getCategories,};
  }
};

然后我渲染产品;

<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' />
                    &nbsp;&nbsp;
                    <span className={classes.productCardBtnWrapper}>
                      Add to Cart
                    </span>
                  </>
                ) : (
                  <>
                    <RemoveShoppingCartIcon fontSize='small' /> &nbsp;&nbsp;
                    <span className={classes.productCardBtnWrapper}>
                      Out of Stock
                    </span>
                  </>
                )}
              </Button>
            </div>
          </div>
        </Grid>
      ))}
    </Grid>
本文链接:https://www.f2er.com/892.html

大家都在问