我正在使用电影收藏应用程序,其中有一个包含电影列表的页面。我想添加基于年份,类型和等级过滤电影的功能,并且我想按字母,年份和等级对它进行排序。我如何通过使用redux来完成该任务以及如何通过使用单个状态对象来做出反应。
首先,我们应该创建组件以显示电影列表。
注意,这是一个纯粹的无状态组件,我们不在那里进行排序或过滤,而只是渲染派生的道具:
// 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;
我们将在应用程序状态下存储电影以及所有过滤和排序数据。我们需要创建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
。
让我们创建PaneContainer
以提供对Pane
组件的排序和过滤数据:
// 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);
我有一个带有搜索面板的网页。搜索面板有几个输入字段:id, size,... 我想要的是当用户设置搜索值(例如:id=123和size=45)并按下搜索按钮时: Redux reducer中的searchState应更新为新的搜索值(id=123,size=45) URL应更改为“http://mydomain/home?id=123 另一方面,如果用户将URL更改为超文本传输协议://myDom
我有这个对象,我需要过滤它。 我只需要在“数据”中输入“isEnabled”为真的值的ID
问题内容: 我有两个阵列。我正在用PubSidebar过滤基于groupKey。 如果父母重视:日记或存款或任何价值或角色:公共,我在传递内容数组内的对象时遇到问题。我必须在基于的内容数组中传递值。 如果存在Journals and Deposits,则在内容数组内添加Journals and Deposit数据,包括公共数据。(三个对象) 如果存在Journals,则将Contents数组内的J
问题内容: 根据文档,反应应用程序的状态必须是可序列化的。那班呢? 假设我有一个ToDo应用。到目前为止,每个项目都具有,等属性。现在,我想对不可序列化的对象使用方法。即这将重命名待办事项,做了很多其他的东西。 据我了解,我可以在某处声明函数,然后通过props将该函数传递给组件。 我在声明某个地方时遇到两个问题:1)在哪里?在减速器中?在应用程序的化简器中很难找到所有方法。2)传递此功能。真?我
问题内容: 我们提供了讲座和章节的列表,用户可以在其中选择和取消选择它们。这两个列表存储在redux存储中。现在,我们希望在url的hash标签中保留选定的演讲段和章节段的表示形式,并且对该URL所做的任何更改也应更改存储(双向同步)。 使用react-router甚至react-router- redux 的最佳解决方案是什么? 我们找不到真正的好例子,其中react路由器仅用于维护url的ha
我们有一个讲座和章节的列表,用户可以在其中选择和取消选择它们。这两个列表存储在redux存储中。现在,我们希望在url的哈希标记中保留所选讲座段塞和章节段塞的表示,对url的任何更改也应该更改存储(双向同步)。 什么是最好的解决方案,使用反应路由器或甚至反应路由器redux? 我们真的找不到一些好的例子,其中react路由器只用于维护url的哈希标记,并且只更新一个组件。