如何使用布局组件并使用 React redux 工具包更改带有 ID 的数据

How to use a layout component and change the data with the ID using react redux toolkit

我正在尝试为我在多个页面上使用的布局制作一个组件,并希望根据页面更改数据。

我设置了一个商店并立即获取每个页面的数据,但是有 4 个页面具有相同的布局,我想使布局成为它自己的组件。我不知道怎么做,所以它会根据categoryID改变。

下面是我的代码的一小部分。


const Books = () => {
const products = useSelector(state => state.products)
                return (
                     <>
                        <SideMenu/>
                          {products.map(product => (
                            <div key={product.categoryId + product.description} >
                                 {(product.sortOrder === 0 && product.categoryId === 2 )? <>
                                    <img className="img-fluid"
                                        src={product.imagePath}
                                        alt="book"
                                        id="book"
                                    />
                                    </>
                                    :<> </>}

                                <div className="mainBack">
                                {(product.sortOrder === 0) && (product.categoryId === 2) && (product.description !== null) ? <>
                                        <div className="row">
                                            <div className=" col" 
                                                 id="description" >
                                                {product.description}
                                            </div>
                                        </div>
                                    </> 
                                     : <> </>}
                    </>
export default Books;

我希望有一个 Layout.js 组件,其中包含所有 HTML 和带有 ID 变量的数据,我可以在另一个组件中更改。

看起来您正在尝试做的是过滤产品,以便只显示带有 (product.sortOrder === 0) && (product.categoryId === 2) 的产品。在不同的页面上,您想使用不同的过滤器执行相同的操作。您可以使用 selector 函数 select 仅 select 您想要的产品,而不是 select 使用 useSelector 的所有产品。然后我们可以从 JSX 中删除那些条件检查。

让我们让它变得非常灵活。首先让我们创建一个组件,它接受一个道具 product,它是一个单一的产品,并以类别页面的格式呈现它,可能是某种“tile”。

const ProductTile = ({ product }) => {
  return (
    <div>
      <img className="img-fluid" src={product.imagePath} alt="book" id="book" />
      <div className="mainBack">
        {
          // is this check necessary? Do some products really have a `null` description?
          product.description !== null && (
            <div className="row">
              <div className=" col" id="description">
                {product.description}
              </div>
            </div>
          )
        }
      </div>
    </div>
  );
};

然后让我们制作一个组件,该组件采用产品数组 products 并呈现包含这些产品的产品列表页面。这是您包含 <SideMenu/> 等布局元素的地方。

const ProductListingPage = ({ products }) => {
  return (
    <div>
      <SideMenu />
      {products.map((product) => (
        <ProductTile
          product={product}
          // I hate this key! do you have a `product.id` that you can use?
          // needs a fallback if product.description might be null
          // but this is a problem because you will have non-unique keys
          key={product.categoryId + (product.description || "")}
        />
      ))}
    </div>
  );
};

这两个是所谓的“展示”组件,因为它们所做的一切都是从道具中获取数据并展示它。他们没有任何状态或调用任何钩子。

所以现在我们要创建一个包含逻辑的“容器”组件。该组件将 categoryId 作为道具。它将 select 该类别中的所有产品,并根据它们的 sortOrder 对它们进行排序。然后它将这些产品传递给处理渲染的 ProductListingPage

大部分逻辑在selector中,我们可以将其定义为一个单独的函数。我正在使用带有自定义比较器函数的 lodash sortBy function because it is easy to write and understand compared to using Array.sort

import React from "react";
import { useSelector } from "react-redux";
import sortBy from "lodash/sortBy";

// double arrow function takes a categoryId and returns a selector function for that category
const selectCategoryProducts = (categoryId) => 
  (state) => {
    // filter to only those that match the categoryId
    const catProducts = state.products.filter(
      (product) => product.categoryId === categoryId
    );
    // sort them by sortOrder using lodash sortBy
    return sortBy(catProducts, "sortOrder");
  };

const CategoryProductsPage = ({categoryId}) => {
  const products = useSelector(selectCategoryProducts(categoryId));
  return (
    <ProductListingPage products={products}/>
  )
}

ProductListingPage 作为独立于 CategoryProductsPage 的组件,这意味着您可以使用不同的 select 产品创建产品列表页面,例如最新产品(不考虑类别)、特色产品等