Redux:按点击排序的API数据响应

问题描述 投票:3回答:1

我正在尝试开发一个应用程序,即显示来自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道具。

Example API response

我想对它们进行排序,例如,将created_at考虑在内。这可以通过按钮点击来处理(还有其他按钮可以说喜欢金额等等)。我试图在mapStateToProps中这样做,直到我意识到用onClick处理程序调用它是不可能的。

正如我读过this post,我认为这是一个好主意,但是,我不确定,我怎么能处理动作创建者的请求。

有没有办法用onclick处理程序调用排序函数?

javascript reactjs redux
1个回答
3
投票

您可以采用的一种方法是使用Redux的reduxjs/reselect等库来计算基于状态的派生数据,在这种情况下,基于某些对象键和/或方向对项目进行排序。选择器是可组合的,并且通常是高效的,因为它们不会被重新计算,除非它的一个参数发生变化。此方法是为reducer的状态添加属性以用于排序键和排序顺序。当这些通过actions / reducers在商店中更新时,选择器使用state来导出生成的排序顺序中的元素。您可以在任何连接的组件中使用已排序的项目。

我已经尽力重新创建一个完整的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 - 更新初始状态以跟踪排序键和/或排序方向,其中照片对象存储在子属性(如items)中:

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,展示了行动中的功能。它包括受控组件,例如和触发分派操作的分派。

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.