我正在尝试开发一个应用程序,该应用程序显示给定关键字的Unsplash照片.我设法使用unsplash.js获取特定的照片:
动作:
export function fetchPhotos(term) {
const unsplash = new Unsplash({
applicationId:
"id",
secret: "secret",
callbackUrl: "callback"
});
const response = unsplash.search
.photos(term, 1, 20)
.then(toJson)
.then(json => json);
return {
type: FETCH_PHOTOS,
payload: response
};
}
export function setCategory(term) {
return {
type: SET_CATEGORY,
categories: [term]
};
}
export function sortPhotos(attribute) {
return {
type: SORT_PHOTOS,
attribute
}
}
渲染照片的组件:
import React, { Component } from "react";
import { connect } from "react-redux";
import SinglePhoto from "../components/SinglePhoto";
class PhotoList extends Component {
renderPhotos() {
const { photos } = this.props;
console.log(photos);
if (!photos) {
return <p>Loading...</p>;
}
return photos.map(photo => {
const url = photo.urls.full;
const id = photo.id;
const alt = photo.description;
return <SinglePhoto url={url} key={id} alt={alt} />;
});
}
render() {
return <div>{this.renderPhotos()}</div>;
}
}
function mapStateToProps(state) {
return {
photos: state.photos,
categories: state.categories
};
}
export default connect(mapStateToProps)(PhotoList);
和减速器:
import { FETCH_PHOTOS, SORT_PHOTOS } from "../actions/types";
export default function(state = [], action) {
switch (action.type) {
case FETCH_PHOTOS:
return [...action.payload.results];
case SORT_PHOTOS:
break;
default:
return state;
}
}
我正在努力做的是根据特定术语对从API接收的数据数组进行实际排序.响应是一个对象数组,无法在我要设置逻辑的外部组件(称为按钮)中调用它:
class Buttons extends Component {
render() {
const { created_at: date } = this.props.photos;
console.log(this.props);
return (
<div className="buttons">
{/* <button onClick={() => this.props.sortPhotos(date)}>Sort by creation date</button> */}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
photos: state.photos
}
}
const mapDispatchToProps = (dispatch) => bindActionCreators({sortPhotos}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Buttons);
因为我需要遍历照片才能实际接收其created_at道具.
我想对它们进行排序,例如,将created_at考虑在内.这可以通过单击按钮来处理(还有其他按钮,比如说喜欢数量等等).我尝试在mapStateToProps中执行此操作,直到意识到无法使用onClick处理程序调用它为止.
当我阅读this post时,我认为这将是一个好主意,但是,我不确定如何由动作创建者处理此请求.
有什么办法可以用onclick处理程序调用排序功能?
解决方法:
您可以采用的一种方法是使用Redux reduxjs/reselect之类的库根据状态来计算派生数据,在这种情况下,根据某些对象键和/或方向对项目进行排序.选择器是可组合的,通常很有效,因为除非对其参数之一进行更改,否则它们不会重新计算.这种方法是在归约器的状态中为排序键和排序顺序添加属性.由于这些是通过操作/归约器在商店中更新的,因此选择器使用状态以结果排序的顺序派生元素.您可以在任何连接的组件中使用排序的项目.
我已经尽力重新创建了一个完整的example,包括动作,缩减器,选择器和商店结构.
动作-创建用于设置排序键/方向的动作.我的示例使用redux-thunk处理异步操作,但这完全没有必要:
export const SET_SORT = 'SET_SORT';
const setSort = (sortDirection, sortKey) => ({
type: SET_SORT,
sortDirection,
sortKey
});
export const sort = (sortDirection = 'desc', sortKey = 'created_at') => dispatch => {
dispatch(setSort(sortDirection, sortKey));
return Promise.resolve();
};
Reducer-更新了初始状态,以跟踪照片对象中存储的照片对象(例如项)的排序键和/或排序方向:
const initialState = {
isFetching: false,
sortDirection: null,
sortKey: null,
items: []
};
const photos = (state = initialState, action) => {
switch (action.type) {
case FETCH_PHOTOS:
return {
...state,
isFetching: true
};
case RECEIVE_PHOTOS:
return {
...state,
isFetching: false,
items: action.photos
};
case SET_SORT:
return {
...state,
sortKey: action.sortKey,
sortDirection: action.sortDirection
};
default:
return state;
}
};
选择器-使用重新选择,创建选择器来检索项目/照片,sortOrder和sortDirection.显然可以增强排序逻辑以处理其他键/条件/等:
import { createSelector } from 'reselect';
const getPhotosSelector = state => state.photos.items;
const getSortKeySelector = state => state.photos.sortKey;
const getSortDirectionSelector = state => state.photos.sortDirection;
export const getSortedPhotosSelector = createSelector(
getPhotosSelector,
getSortKeySelector,
getSortDirectionSelector,
(photos, sortKey, sortDirection) => {
if (sortKey === 'created_at' && sortDirection === 'asc') {
return photos.slice().sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
} else if (sortKey === 'created_at' && sortDirection === 'desc') {
return photos.slice().sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
} else {
return photos;
}
}
);
组件-使用选择器渲染项目.通过按一下排序键和/或排序顺序的按钮单击来触发调度动作的分派.链接的示例结合使用下拉菜单和单击按钮来设置排序键/顺序:
import { getSortedPhotosSelector } from './selectors';
// ...
handleClick() {
this.props.dispatch(sort('desc', 'created_at'));
}
render() {
const { sortDirection, sortKey, items } = this.props;
<ul>
{items.map(item => <li key={item.id}>{item.created_at}</li>)}
</ul>
<button type="button" onClick={this.handleClick}>SORT</button>
}
const mapStateToProps = state => ({
items: getSortedPhotosSelector(state),
sortKey: state.photos.sortKey,
sortDirection: state.photos.sortDirection
});
export default connect(mapStateToProps)(PhotoList);
这是StackBlitz,演示了实际的功能.它包括受控组件,例如和触发排序操作的分派.
希望有帮助!