如何在redux中过滤和排序相同的对象状态数组? [英] How to filter and sort the same array of object state in redux?

查看:38
本文介绍了如何在redux中过滤和排序相同的对象状态数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发电影收藏应用程序,其中有一个包含电影列表的页面.我想添加根据年份、流派和评级过滤电影的功能,并且我想按字母顺序、年份和评级对其进行排序.我如何通过使用 redux 来实现这一点,并通过使用单个状态对象做出反应.

解决方案

首先,我们应该创建一个组件来显示电影列表.
注意,这是一个纯粹的无状态组件,我们不会在那里进行排序或过滤,只是渲染派生的道具:

//Movies.js从反应"导入反应;功能电影({电影}){返回 (<ul>{movies.map((m, i) =><li key={i}>{m.year} - {m.title}.({m.genre}) - {m.rating}</li>)});}导出默认电影;

接下来我们将创建另一个无状态组件,其中将包含排序和过滤视图.
这里我们还渲染道具,并为 select 元素提供回调:

//Pane.js从反应"导入反应;功能窗格({选择年份,选择的流派,选择评级,年 = [],流派 = [],评分 = [],排序,onYearChange,关于流派变化,onRatingChange,onSortingChange,}) {返回 (<div><div>过滤器:<div>年:<选择默认值={selectedYear}onChange={e =>onYearChange(e.target.value)}><option value="all" >All</option>{years.map((y, i) =><option key={i} value={y}>{y}</option>)}</选择>

<div>类型:<选择defaultValue={selectedGenre}onChange={e =>onGenreChange(e.target.value)}><option value="all" >All</option>{genres.map((g, i) =><option key={i} value={g}>{g}</option>)}</选择>

<div>评分:<选择默认值={selectedRating}onChange={e =>onRatingChange(e.target.value)}><option value="all" >All</option>{ratings.map((r, i) =><option key={i} value={r}>{r}</option>)}</选择>

<div>选择排序:<选择默认值={排序}onChange={e =>onSortingChange(e.target.value)}><option value="alphabetically">Alphabetically</option><option value="year">Year</option><option value="rating">Rating</option></选择>

);}导出默认窗格;

我们将在应用状态中存储电影和所有过滤和排序数据.我们需要创建reducer,来处理排序和过滤操作:

//reducers.js常量项 = [{title: '疯狂的麦克斯',年份: 2015,评分:8,类型:'幻想',}, {title: '蜘蛛侠 2',年份: 2014,评分:7,类型:'幻想',}, {title: '钢铁侠3',年份: 2013,评分:7,类型:'幻想',}, {title: 'Dumb and Dumber To',年份: 2014,评分:5,类型:喜剧",}, {标题:'泰德 2',年份: 2015,评分:6,类型:喜剧",}];导出默认函数moviesReducer(state = {电影:物品,年份:'全部',评分:全部",类型:'所有',排序:'年',}, 行动) {开关(动作.类型){案例SET_YEAR":返回 {...状态,年:行动年,};案例SET_RATING":返回 {...状态,评级:action.rating,};案例SET_GENRE":返回 {...状态,流派:动作.流派,};案例SET_SORTING":返回 {...状态,排序:action.sorting,};默认:返回状态;}}

为了给无状态组件提供数据,我们应该使用containers.
让我们创建PaneContainer来为Pane提供排序和过滤数据> 组件:

//PaneContainer.js从'react-redux'导入{连接};从'./Pane'导入窗格;//简单的辅助函数,它通过给定的键从状态返回所有过滤器.功能getFilters(键,电影){返回movies.reduce((acc,movie) => {如果(!acc.includes(电影[key])){返回 [...acc, 电影 [key]];}返回acc;}, []);}函数 mapStateToProps(state, props) {const { 排序,年份,流派,评级 } = 状态;返回 {选择年份:年份,selectedGenre:流派,selectedRating:评级,年:getFilters('year', state.movi​​es),流派:getFilters('genre', state.movi​​es),评分:getFilters('rating', state.movi​​es),排序,};}函数 mapDispatchToProps(dispatch, props) {返回 {//在这里,我们提供带有调度函数的回调.onYearChange(年){派遣({类型:'SET_YEAR',年,});},onGenreChange(流派){派遣({类型:'SET_GENRE',类型,});},onRatingChange(评级){派遣({类型:'SET_RATING',评分,});},onSortingChange(排序){派遣({类型:'SET_SORTING',排序,});},};}导出默认连接(mapStateToProps,mapDispatchToProps)(窗格);

最后,我们将创建 MoviesContainer,它将为 Movies 组件提供可见的电影:

//MoviesContainer.js从'react-redux'导入{连接};从'./Movies'导入电影;//从状态中获取可见的电影.功能 getVisibleMovies(年份,流派,评级,排序,电影){回归电影.filter(m => {返回 ((year == 'all' || year == m.year) &&(流派 == '所有' || 流派 == m.genre) &&(评级 == '所有' || 评级 == m.rating));}).sort((a, b) => {如果(排序=='年份'){返回 b.year - a.year;}如果(排序=='评级'){返回 b.rating - a.rating;}如果(排序 == '按字母顺序'){返回 a.title >b.标题?1 : a.title <b.标题?-1:0;}});}函数 mapStateToProps(state) {const { 年,流派,评级,排序,电影 } = 状态;返回 {电影:getVisibleMovies(年份,流派,评级,排序,电影),};}导出默认连接(mapStateToProps)(电影);

I am working on movie collection app , where i have a page with movie list. I want to add the functionality of filtering the movie based on year, genre and rating and also i want to sort it alphabetically ,year and rating. How can i accomplish that by using redux and react by using single state object.

解决方案

First, we should create component to display movies list.
Note, this is a pure stateless component, we are not making sorting or filtering there, just rendering derived props:

// Movies.js

import React from 'react';

function Movies({ movies }) {
  return (
    <ul>
      {movies.map((m, i) =>
        <li key={i}>{m.year} - {m.title}.({m.genre}) - {m.rating}</li>
      )}
    </ul>
  );
}

export default Movies;

Next we will create another stateless component, which will contain sorting and filters view.
Here we are also rendering props, and providing callback to select elements:

// Pane.js

import React from 'react';

function Pane({
  selectedYear,
  selectedGenre,
  selectedRating,
  years = [],
  genres = [],
  ratings = [],
  sorting,
  onYearChange,
  onGenreChange,
  onRatingChange,
  onSortingChange,
}) {
  return (
    <div>
      <div>
        Filters:
        <div>
          Year:
          <select
            defaultValue={selectedYear}
            onChange={e => onYearChange(e.target.value)}
          >
            <option value="all" >All</option>
            {years.map((y, i) =>
              <option key={i} value={y}>{y}</option>
            )}
          </select>
        </div>
        <div>
          Genre:
          <select
            defaultValue={selectedGenre}
            onChange={e => onGenreChange(e.target.value)}
          >
            <option value="all" >All</option>
            {genres.map((g, i) =>
              <option key={i} value={g}>{g}</option>
            )}
          </select>
        </div>
        <div>
          Rating:
          <select
            defaultValue={selectedRating}
            onChange={e => onRatingChange(e.target.value)}
          >
            <option value="all" >All</option>
            {ratings.map((r, i) =>
              <option key={i} value={r}>{r}</option>
            )}
          </select>
        </div>
      </div>
      <div>
        Select sorting:
        <select
          defaultValue={sorting}
          onChange={e => onSortingChange(e.target.value)}
        >
          <option value="alphabetically">Alphabetically</option>
          <option value="year">Year</option>
          <option value="rating">Rating</option>
        </select>
      </div>
    </div>
  );
}

export default Pane;

We will store movies and all filtering and sorting data in app state. We need create reducer, to handle sorting and filtering actions:

// reducers.js

const items = [{
  title: 'Mad max',
  year: 2015,
  rating: 8,
  genre: 'fantasy',
}, {
  title: 'Spider man 2',
  year: 2014,
  rating: 7,
  genre: 'fantasy',
}, {
  title: 'Iron man 3',
  year: 2013,
  rating: 7,
  genre: 'fantasy',
}, {
  title: 'Dumb and Dumber To',
  year: 2014,
  rating: 5,
  genre: 'comedy',
}, {
  title: 'Ted 2',
  year: 2015,
  rating: 6,
  genre: 'comedy',
}];

export default function moviesReducer(state = {
  movies: items,
  year: 'all',
  rating: 'all',
  genre: 'all',
  sorting: 'year',
}, action) {
  switch (action.type) {
    case 'SET_YEAR':
      return {
        ...state,
        year: action.year,
      };
    case 'SET_RATING':
      return {
        ...state,
        rating: action.rating,
      };
    case 'SET_GENRE':
      return {
        ...state,
        genre: action.genre,
      };
    case 'SET_SORTING':
      return {
        ...state,
        sorting: action.sorting,
      };
    default:
      return state;
  }
}

To provide data to stateless components, we should use containers.
Let's create PaneContainer to provide sorting and filtering data to Pane component:

// PaneContainer.js

import { connect } from 'react-redux';
import Pane from './Pane';

// Simple helper function, which return all filters from state by given key.
function getFilters(key, movies) {
  return movies.reduce((acc, movie) => {
    if (!acc.includes(movie[key])) {
      return [...acc, movie[key]];
    }
    return acc;
  }, []);
}

function mapStateToProps(state, props) {
  const { sorting, year, genre, rating } = state;
  return {
    selectedYear: year,
    selectedGenre: genre,
    selectedRating: rating,
    years: getFilters('year', state.movies),
    genres: getFilters('genre', state.movies),
    ratings: getFilters('rating', state.movies),
    sorting,
  };
}

function mapDispatchToProps(dispatch, props) {
  return {
    // Here, we are providing callbacks with dispatching functions.
    onYearChange(year) {
      dispatch({
        type: 'SET_YEAR',
        year,
      });
    },
    onGenreChange(genre) {
      dispatch({
        type: 'SET_GENRE',
        genre,
      });
    },
    onRatingChange(rating) {
      dispatch({
        type: 'SET_RATING',
        rating,
      });
    },
    onSortingChange(sorting) {
      dispatch({
        type: 'SET_SORTING',
        sorting,
      });
    },
  };
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Pane);

And finally, we will create MoviesContainer which will provide visible movies to Movies component:

// MoviesContainer.js

import { connect } from 'react-redux';
import Movies from './Movies';

// Getting visible movies from state.
function getVisibleMovies(year, genre, rating, sorting, movies) {
  return movies
    .filter(m => {
      return (
        (year == 'all' || year == m.year) &&
        (genre == 'all' || genre == m.genre) &&
        (rating == 'all' || rating == m.rating)
      );
    })
    .sort((a, b) => {
      if (sorting == 'year') {
        return b.year - a.year;
      }
      if (sorting == 'rating') {
        return b.rating - a.rating;
      }
      if (sorting == 'alphabetically') {
        return a.title > b.title ? 1 : a.title < b.title ? -1 : 0;
      }
    });
}

function mapStateToProps(state) {
  const { year, genre, rating, sorting, movies } = state;
  return {
    movies: getVisibleMovies(year, genre, rating, sorting, movies),
  };
}

export default connect(mapStateToProps)(Movies);

这篇关于如何在redux中过滤和排序相同的对象状态数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆