Redux: ответ данных API отсортирован по клику - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь разработать приложение, которое показывает фотографии из 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);

Поскольку мне нужно было бы перебрать фотографии, чтобы фактически получить их реквизиты созданного_тата.

Example API response

Я бы хотел отсортировать их, например, принимая во внимание созданный_кат. Это будет обработано нажатием кнопки (будут другие кнопки, скажем, количество лайков и т. Д.). Я пытался сделать это в mapStateToProps до того момента, как понял, что это невозможно будет вызвать с помощью обработчика onClick.

Поскольку я прочитал этот пост , я подумал, что это будет отличная идея, однако я не уверен, как я могу обработать этот запрос создателем действия.

Можно ли как-нибудь вызвать функцию сортировки с помощью обработчика onclick?

1 Ответ

0 голосов
/ 31 августа 2018

Один из подходов, который вы можете использовать, - это использование библиотеки, такой как Redux reduxjs / reselect , для вычисления производных данных на основе состояния, в этом случае отсортированные элементы на основе некоторого ключа объекта и / или направления. Селекторы являются составными и обычно эффективны, поскольку они не пересчитываются, если не изменяется один из его аргументов. Этот подход добавляет свойства в состояние редуктора для ключа сортировки и порядка сортировки. Поскольку они обновляются в хранилище с помощью действий / редукторов, селектор использует состояние для получения элементов в результирующем отсортированном порядке. Вы можете использовать отсортированные элементы в любом подключенном компоненте.

Я старался изо всех сил воссоздать полный пример , включая действия, редукторы, селекторы и структуру магазина.

Действия - Созданы действия для установки ключа / направления сортировки. Мой пример использует 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();
};

Редуктор - Обновлено начальное состояние для отслеживания ключа сортировки и / или направления сортировки с фото-объектами, хранящимися в дочернем свойстве, таком как 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. Логика сортировки, очевидно, может быть улучшена для обработки других ключей / условий / etc:

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 , демонстрирующий функциональность в действии. Он включает в себя контролируемые компоненты, такие как и для запуска отправки действия сортировки.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...