2016-06-30 1 views
2

나는 영화 목록이있는 페이지가있는 영화 수령 앱을 만들고 있습니다. 나는 년, 장르 및 등급을 기반으로 영화를 필터링하는 기능을 추가하고 알파벳순, 연도 및 등급 순으로 정렬하고 싶습니다. 어떻게하면 redux를 사용하고 단일 상태 객체를 사용하여 반응 할 수 있습니까?redux에서 동일한 객체 상태 배열을 필터링하고 정렬하는 방법은 무엇입니까?

+0

* 충분한 명성을하지 않습니다 마지막으로, 우리는 Movies 구성 요소에 볼 영화를 제공 할 것입니다 MoviesContainer를 생성합니다

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

그리고 :
의이 Pane 구성 요소에 데이터를 정렬 및 필터링 제공하기 위해 PaneContainer을 만들어 보자 'key = {i}'를 주석 처리하고'getVisibleMovies'를 정렬하면 전체 목록과 목록 항목이 다시 렌더링됩니다. – uschen

답변

29

먼저 영화 목록을 표시 할 구성 요소를 만들어야합니다.
참고, 이것은 우리가 파생 소품 렌더링,이 정렬 또는 필터링 제작되지 않은 순수한 상태 비 저장 구성 요소입니다

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

다음으로 우리가 정렬 및 필터보기를 포함 다른 비 저장 구성 요소를 생성합니다.
여기에 우리는 또한 소품을 렌더링하고, 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; 

. 우리는 정렬 및 필터링 작업을 처리하기 위해, 감속기를 만들 필요

// 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을 사용해야 무 구성 요소에 데이터를 제공하기 위해.

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

무비 컨테이너는 어디에 있습니까? Movies 구성 요소를 가져온 다음 redux 저장소에 연결했습니다. 이것은 좋은 습관처럼 보이지 않습니다. 이 코드가 작동합니까? –

+0

@IsaacPak'영화 '구성 요소는 대답의 시작 부분에 정의되어 있습니다. 'MoviesContainer'는 결국 정의됩니다. 'connect'를 사용하여 redux store에서 컴포넌트로 데이터를 제공하는 것이 일반적인 접근법입니다. – 1ven

+0

확인. 내 컨테이너를 상점에 연결했습니다. 그러나 이제는이 [docs] (http://redux.js.org/docs/basics/UsageWithReact.html)를 검토 했으므로 이제 코드가 더 이해가됩니다. 감사! –