reactjs - 如何在redux中过滤和排序相同的对象状态数组?

标签 reactjs redux react-redux

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

最佳答案

首先,我们应该创建组件来显示电影列表。
注意,这是一个纯粹的无状态组件,我们不会在那里进行排序或过滤,只是渲染派生的 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;

接下来我们将创建另一个无状态组件,它将包含排序和过滤 View 。这里我们也渲染 Prop ,并提供对 select 的回调。元素:

// 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;

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

// 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;
  }
}

为了向无状态组件提供数据,我们应该使用 containers .让我们创建 PaneContainerPane 提供排序和过滤数据成分:

// 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);

最后,我们将创建 MoviesContainer它将向 Movies 提供可见的电影成分:

// 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);

关于reactjs - 如何在redux中过滤和排序相同的对象状态数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38133137/

相关文章:

reactjs - 当应用程序在 native 后台时如何更新服务中的纬度和经度

javascript - Redux 表单 : MapStateToProps is breaking form

javascript - 使用 Redux 的集中式音频单元?

javascript - 了解 UI 何时在 React/Redux 中准备就绪

reactjs - 安装了react-redux和redux模块后,无法解析connected-react-router中的模块 'react-redux'

javascript - 如何将 Prop 传递给循环内的样式化组件

android - 带有 React Native 的 Nox 模拟器

javascript - 传递 props 时我应该总是写 this.props 吗?

reactjs - React-Redux:在 React 组件中使用操作创建器

javascript - 如何避免嵌套的三元运算符