How to filter and sort the same array of object state in redux?

匿名 (未验证) 提交于 2019-12-03 01:25:01

问题:

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.

回答1:

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 (     
    {movies.map((m, i) =>
  • {m.year} - {m.title}.({m.genre}) - {m.rating}
  • )}
); } 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 (     
Filters:
Year:
Genre:
Rating:
Select sorting:
); } 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 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!