本文介绍了在React中构建可链接的过滤器组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

构建可重复使用的,可链接的过滤器组件的最反应"方式是什么?

What's the most "React"y way to build reusable, chainable filter components?

假设我有一个输入数组:

Let's say I have an input array:

[
{name: 'Generic t-shirt', size: 'xxl', available: 35},
{name: 'Generic t-shirt', size: 'md', available: 2},
{name: 'Generic t-shirt', size: 'sm', available: 5},
{name: 'Really awesome shirt', size: 'md', available: 0}
]

然后使用关键字搜索名称,下拉列表中的大小以及已售完"布尔值复选框以了解可用性.

And a keyword search for the name, a dropdown for size, and a "sold out" boolean checkbox for availability.

现在,我在渲染循环中包含了过滤代码:

Right now, I have the filtering code inside the rendering loop:

const [productsFilteredByFullText, setProductsFilteredByFullText] = useState;
const [productsFilteredBySize, setProductsFilteredBySize] = useState;
const [productsFilteredByAvailability, setProductsFilteredByAvailability] = useState;

const searchResults = useMemo(() => {
    let filteredProducts = eventsFromAPI; // array of products as input

    filteredProducts = filteredEvents.filter(product => fullTextFilter(product));
    filteredProducts = filteredEvents.filter(product => sizeFilter(product));
    filteredProducts = filteredEvents.filter(product => availabilityFilter(product));

    return filteredProducts;
}, [productsFilteredByFullText, productsFilteredBySize, productsFilteredByAvailability]);

以及JSX中的UI:

<div>

    // Fulltext search
    <input
        type="text"
        placeholder="Keyword search"
        value={searchTerm}
        onChange={fullTextHandler}
    />


    // Size dropdown
    <Dropdown
        options={allAvailableSizes}
        onChange={sizeHandler}
    />

    // Sold out checkbox
    <input
        name="soldout"
        type="checkbox"
        checked={productsFilteredByAvailability}
        onChange={availabilityHandler}
    />

    <h1>Results</h1>
    {filteredProducts.map(item => (
        <Product item={item} />
    ))}
</div>

这有效,但是根本不是非常可重用的.假设我还有另一种产品围巾,它们都是一种尺寸,但是我仍然希望能够重复使用过滤器组件和逻辑来命名和使用.

This works, but is not very reusable at all. Let's say I have another product category, scarves, that are all one size, but I still want to be able to re-use the filter component and logic for name and availability.

是否有一种方法可以将过滤器逻辑和演示JSX模块化/组件化为单独的过滤器组件,并能够将它们任意地链接在一起?像这样的伪代码:

Is there a way to modularize/componentize BOTH the filter logic AND the presentation JSX into separate filter components, and be able to chain them together arbitrarily? Something like this pseuocode:

<TShirtList>
<NameFilter/>
<SizeFilter/>
<AvailabilityFilter/>
</TShirtList>

<ScarfList>
<NameFilter/>
<AvailabilityFilter/>
</ScarfList>

<ServicesList>
<NameFilter/>
</ServicesList>

每个过滤器都是自己的组件,可以插入任何地方的任何产品系列中吗?就像React组件如何提供其他组件可以使用的自己的逻辑/功能一样(输入产品数组,过滤的产品数组+ JSX UI输出,但可链接).

So that each filter is its own component, able to be inserted into any array of products anywhere? Like how can a React component also provide its own logic/functions that other components can use (product array in, filtered product array + JSX UI out, but chainable).

这是思考这个问题的正确方法吗?我对如何最好地在体系结构上构建感到困惑.

Is that even the right way to think about this problem...? I'm confused about how to best build this architecturally.

推荐答案

该问题的答案

我建议单独显示&数据逻辑通过使用钩子.将所有与数据相关的逻辑移到一个钩子中,然后将该钩子导入到react组件中.

I suggest separate display & data logic by using hooks. Move all data related logic into a hook, and import that hook to a react component.

// useProducts.js
const useProducts = () => {
  const [products, setProducts = useState([]);
  const [filters, setFilters] = useState({}); // eg. filters = { size: 'large', availability: 'instock' }

  // Get all products on initial load
  useEffect(() => {
    fetch(....).then(response => setProducts(response.data));
  }, []);

  // function to set filter.
  const setFilter = (name, value) => {
    setFilters({ ...filters, [name]: value });
  }

  // Loop filters and filter product
  const filteredProducts = [...products];
  for (const [key, value] of Object.entries(filters)) {
    // Get list of products from somewhere.
    filteredProducts = filterProducts.filter(p => p[key] === value);
  }

  return [filteredProducts, { setFilter }];
}

// Product List
import React from 'react';
import useProducts from './useProducts';

const ProductList = (props) => {
  const [products, { setFilter }] = useProducts();

  return (
    <div>
      <div className="toolbar">
        <NameFilter onChange={value => setFilter('name', value)} />
        <SizeFilter onChange={value => setFilter('size', value)} />
        <AvailabilityFilter onChange={value => setFilter('availability', value)} />
      </div>
      <div>
        {products.map(p => <ProductItem {...p} />}
      </div>
    </div>
  );
}

此外,您甚至可以通过在过滤器组件本身中导入{setFilter}对其进行更多模块化.您可以从ProductList中删除"onChange".

Additionally, you can even modularize it more by import { setFilter } in the filter component itself. And you can remove the 'onChange' from the ProductList.

const NameFilter = () => {
  const [, { setFilter }] = useProducts();
  return (
    <input
      type="text"
      onChange={e => setFilter('name', e.target.value)}
    />
  );
}


// And now, we can remove onChange from each filter in Product List component
<div>
  <div className="toolbar">
    <NameFilter />
    <SizeFilter />
    <AvailabilityFilter />
  </div>
  <div>
    {products.map(p => <ProductItem {...p} />}
  </div>
</div>

*注意:上面的代码仅是psuedo,它只是说明了想法.

*Note: Above code is just psuedo, it just shows the idea.

这篇关于在React中构建可链接的过滤器组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 17:42
查看更多