问题:通过复选框过滤对象数组

这是一个React.js过滤器问题,我被困在这里。该问题将电影的静态数据作为对象数组,我们必须根据不同复选框的选中状态过滤该数据。

静态数据:

export const data = [
    {
        id: 1,
        title: 'Batman',
        rating: 1,
        genre: 'Action'
    },
    {
        id: 2,
        title: 'Superman',
        rating: 5,
        genre: 'Comedy'
    },
    {
        id: 3,
        title: 'Spiderman',
        rating: 3,
        genre: 'Thriller'
    },
    {
        id: 4,
        title: 'BananaMan',
        rating: 2,
        genre: 'Action'
    },
    {
        id: 5,
        title: 'OrangeMan',
        rating: 4,
        genre: 'Drama'
    }
];

抽象的 UI 有以下图片,代表 2 种类型的过滤器。

  • 评分

  • 类型

截屏:

过滤器截图

两个过滤器都在 UI 上呈现为复选框。所以,我创建了一个名为Checkboxes的组件,它将采用一个名为list的道具,它是一个对象数组。

这个list代表唯一的ids复选框,这将帮助我们跟踪复选框的checkedunchecked状态。不同的复选框id将保存在一个数组的状态中。

const [checkedArray, setCheckedArray] = useState([]);

最后,我在名为App.js的父组件内渲染了这个Checkboxes组件两次。一个用于评级,另一个用于流派。

列表:

export const listCheckboxesRating = [
    {
        id: 0,
        name: 'rating',
        label: 'Any Rating'
    },
    {
        id: 1,
        name: 'rating1',
        label: 'Rating 1'
    },
    {
        id: 2,
        name: 'rating2',
        label: 'Rating 2'
    },
    {
        id: 3,
        name: 'rating3',
        label: 'Rating 3'
    },
    {
        id: 4,
        name: 'rating4',
        label: 'Rating 4'
    },
    {
        id: 5,
        name: 'rating5',
        label: 'Rating 5'
    }
];

export const listCheckboxesGenre = [
    {
        id: 0,
        name: 'genre',
        label: 'Any Genre'
    },
    {
        id: 1,
        name: 'action',
        label: 'Action'
    },
    {
        id: 2,
        name: 'comedy',
        label: 'Comedy'
    },
    {
        id: 3,
        name: 'drama',
        label: 'Drama'
    },
    {
        id: 4,
        name: 'thriller',
        label: 'Thriller'
    }
];

复选框组件:

import {useState} from 'react';
import {handleToggle} from '../../utils';

const Checkboxes = ({list, handleFilters}) => {
    const [checkedArray, setCheckedArray] = useState([]);

    const onChangeHandler = (checkboxId) => {
        const newState = handleToggle(checkboxId, checkedArray);
        setCheckedArray(newState);
        // Update this checked information into Parent Component
        handleFilters(newState);
    };

    return list.map((item, index) => {
        return (
            <div key={index}>
                <input
                    type="checkbox"
                    id={item.name}
                    checked={checkedArray.indexOf(item.id) !== -1}
                    onChange={() => onChangeHandler(item.id)}
                />
                <label htmlFor={item.name}>{item.label}</label>
            </div>
        );
    });
};

export default Checkboxes;

我通过名为handleFilters的函数将这些复选框的整个状态传递给父组件App.js。你可以看到这行代码。

handleFilters(newState);

App.js组件正在保存这些复选框的状态,如下所示:

 const [selected, setSelected] = useState({
        rating: [],
        genre: []
    });

App.js 组件:

import {useState} from 'react';
import Checkboxes from './Checkboxes';
import {data, listCheckboxesRating, listCheckboxesGenre} from '../data';

const App = () => {
    const [movies, setMovies] = useState(data);
    const [selected, setSelected] = useState({
        rating: [],
        genre: []
    });

    /**
     * This function will perform the filtration process based on the key value.
     *
     * @param {number[]} checkboxState - It will take the final state of checkboxes
     * @param {string} key - It will help us to determine the type of filtration
     */
    const handleFilters = (checkboxState, key) => {
        const newFilters = {...selected};
        newFilters[key] = checkboxState;
        // Filtration process
        for (let key in newFilters) {
            if (
                newFilters.hasOwnProperty(key) &&
                Array.isArray(newFilters[key]) &&
                newFilters[key].length > 0
            ) {
                if (key === 'rating') {
                } else if (key === 'genre') {
                }
            }
        }

        // Save the filtered movies and update the state.
        //  setMovies();
        setSelected(newFilters);
    };

    return (
        <div>
            {movies.map((movie) => (
                <div key={movie.id}>
                    <div>Name: {movie.title}</div>
                    <div>Genre :{movie.genre}</div>
                    <div>Rating: {movie.rating}</div>
                    <hr />
                </div>
            ))}

            <div className="row">
                <div className="col">
                    <h1>Filter by Rating</h1>
                    <Checkboxes
                        list={listCheckboxesRating}
                        handleFilters={(checkboxState) =>
                            handleFilters(checkboxState, 'rating')
                        }
                    />
                </div>

                <div className="col">
                    <h1>Filter by Genre</h1>
                    <Checkboxes
                        list={listCheckboxesGenre}
                        handleFilters={(checkboxState) =>
                            handleFilters(checkboxState, 'genre')
                        }
                    />
                </div>
            </div>
        </div>
    );
};

export default App;

两个过滤器的复选框checkedunchecked状态工作正常,并且在父selected状态内使用ids正确更新,如下所示。

 const [selected, setSelected] = useState({
            rating: [1,2,3],
            genre: [2,4]
        });

但这是我卡住的令人困惑的部分。如何映射这些复选框ids并根据这些ids过滤数据?

我在App.js组件handleFilters(checkboxState, key)中定义了一个函数,我想在其中迭代selected状态以执行过滤过程,但我的头脑没有逻辑,我需要帮助。

工作演示:

编辑反应过滤器

存储库链接。

解答

我做了一些重构。

  1. 使数据更通用。
    export const listCheckboxesRating = {
      key: 'rating',
      data: [
        {
          id: 1,
          name: 'rating1',
          label: 'Rating 1',
          value: 1
        },
        ...
    }
  1. 重构 Checkbox 组件,只传递数据。
    <Checkboxes
      list={listCheckboxesGenre}
      handleFilters={handleFilters}
    />

3.使过滤过程具有价值和关键。

    // Filtration process
    let filteredMovies = data.filter((movie) => {
      for (let key in newFilters) {
        if (
          newFilters.hasOwnProperty(key) &&
          Array.isArray(newFilters[key]) &&
          newFilters[key].length > 0
        ) {
          if (
            newFilters[key].findIndex((value) => movie[key] === value) === -1
          ) {
            return false;
          }
        }
      }
      return true;
    });

工作演示:https://codesandbox.io/s/react-filter-forked-gs2b2?fileu003d/src/components/App.js

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐