Используйте async response-select с redux-saga

Я пытаюсь реализовать асинхронную реакцию-выбор (Select.Async). Проблема в том, что мы хотим выполнить выборку в redux-saga. Поэтому, если пользователь что-то набирает, должно срабатывать действие выборки. Затем Saga получает запись и сохраняет ее в магазине. Пока это работает. К сожалению, loadOptions должен возвращать обещание или должен быть вызван обратный вызов. Поскольку вновь полученные параметры распространяются с изменяющимся свойством, я не вижу возможности использовать Select.Async вместе с saga для выполнения вызова async fetch. Какие-либо предложения?

 <Select.Async
   multi={false}
   value={this.props.value}
   onChange={this.onChange}
   loadOptions={(searchTerm) =>  this.props.options.load(searchTerm)}
  />

У меня был хак, когда я назначил обратный вызов переменной класса и разрешил его на componentWillReceiveProps. Такой путь некрасивый и не работал должным образом, поэтому я ищу лучшее решение.

Спасибо


person MethodenMann    schedule 28.03.2017    source источник


Ответы (2)


redux-saga предназначен для обработки побочных эффектов, таких как асинхронное получение параметров для react-select. Вот почему вы должны оставить асинхронный режим на redux-saga. Я никогда не использовал react-select, но просто взглянув на документацию, я решил бы это следующим образом:

Ваш компонент становится очень простым. Просто возьмите value и options в своем магазине redux. optionsRequested является создателем действия для OPTIONS_REQUESTED действия:

const ConnectedSelect = ({ value, options, optionsRequested }) => (
  <Select
    value={value}
    options={options}
    onInputChange={optionsRequested}
  />
)

export default connect(store => ({
  value: selectors.getValue(store),
  options: selectors.getOptions(store),
}), {
  optionsRequested: actions.optionsRequested,
})(ConnectedSelect)

Определение саги отслеживает OPTIONS_REQUESTED действие, которое запускается onInputChange, загружает данные с заданным searchTerm с сервера и отправляет OPTIONS_RECEIVED действие для обновления хранилища redux.

function* watchLoadOptions(searchTerm) {
  const options = yield call(api.getOptions, searchTerm)
  yield put(optionsReceived(options))
}

Другими словами: сделайте свой компонент максимально чистым и обработайте все побочные / асинхронные вызовы в redux-saga

Надеюсь, этот ответ был вам полезен.

person Alex    schedule 02.04.2017
comment
Спасибо за Ваш ответ! Да, я хочу решить проблему именно так, как вы описали. Дело в том, что onChange (loadOptions) response-select, где мне нужно вызвать optionsRequested, ожидает возврата обещания. Это потому, что они ожидают, что вы позвоните туда. Насколько я знаю, нет способа разрешить обещание в компонентах с сагой? - person MethodenMann; 04.04.2017
comment
Привет, я просмотрел документацию здесь: github.com/JedWatson/react-select#usage и onChange не должны возвращать обещание. Это просто обработчик событий. В моем примере я использую onChange для вызова optionsRequested Action Creator, который затем отправляется redux и в конечном итоге обрабатывается saga, который делает запрос на обслуживание. - person Alex; 04.04.2017
comment
Привет. о, извини, теперь я вижу путаницу. Я не хочу использовать значение select как searchTerm в моих сагах. React-select позволяет вводить текст для поиска. В этом поиске я хочу получить новые параметры для моего ответа-выбора, чтобы пользователь мог их выбрать. Это потому, что могут быть тысячи записей, и я не хочу загружать их все изначально. Этого можно достичь с помощью loadOptions, и здесь мне нужно обещание. - person MethodenMann; 04.04.2017
comment
Привет, я тоже запуталась. Прочитав документ еще раз, я имел в виду не onChange, а onInputChange. Я соответствующим образом обновил свой ответ. - person Alex; 04.04.2017
comment
Хорошо, это немного злоупотребление onInputChange. Но если я использую onInputChange и Select Component (Not Select.Async), он работает с saga! Спасибо за ответ! - person MethodenMann; 04.04.2017
comment
Я использую ваш подход, потому что я использую redux saga. Он работает нормально, но когда я печатаю, список не обновляется значениями. Когда я закрываю список и снова открываю его, список в порядке. Я использую onInputKeyDown - person user7334203; 17.06.2017
comment
@decay успешно ли обновляется ваш список? Мой список теперь обновляется, даже если новые значения находятся в состоянии - person user7334203; 12.07.2017
comment
Я использую VirtualizedSelect и redux (а не сагу о redux). В моем onInputChange я хотел бы вызвать свой API после ввода третьего символа, чтобы мой список был отфильтрован. Событие запускает и обновляет состояние с персонажами; Однако после ввода второго символа состояние и значение текстового поля очищаются. Мне интересно, не хватает ли мне чего-то или есть что-то еще, вызывающее значение onInputChange. Заранее извиняюсь, если я задаю свой вопрос не в правильной ветке. @MethodenMann есть ли у вас какой-либо пример того, как заставить его работать с событием OnIputChange, работающим с вызовом API. - person itReverie; 26.02.2018
comment
@ johnwick0831 Я решил проблему в следующем потоке stackoverflow.com/questions/49017633/ - person itReverie; 10.05.2018
comment
Я использую response-select версию 2.4.3. когда новые параметры поступают из магазина, они не обновляются в Select. Я добавил filterOption = {() = ›(true)} в компонент Select в соответствии с github.com/JedWatson/react-select/issues/ - person Sergii Tanchenko; 25.04.2019

Основная идея заключается в том, что вы можете отправлять действия redux, используя контекст приложения из

import React from 'react';
import { connect } from 'react-redux';

import Select from '@components/Control/Form/Skin/Default/Select';
import { reduxGetter, reduxSetter, required as req } from '@helpers/form';
import { companyGetTrucksInit } from "@reduxActions/company";

import AppContext from '@app/AppContext';

const FIELD_NAME = 'truck';

export const getReduxValue = reduxGetter(FIELD_NAME);
export const setReduxValue = reduxSetter(FIELD_NAME);

const SelectCompanyTruck = (props) => {
    const {
        required,
        validate=[]
    } = props;

    const vRules = [...validate];

    if (required)
        vRules.push(req);


    return (
        <AppContext.Consumer>
            {({ dispatchAction }) => (
                <Select
                    loadOptions={(inputValue, callback) => {
                        function handleResponse(response) {
                            const { data: { items } } = response;
                            const options = items.map(i => ({ label: i.name, value: i.id }));

                            callback(options);
                        }

                        dispatchAction(companyGetTrucksInit, { resolve: handleResponse, inputValue });
                    }}
                    name={FIELD_NAME}
                    {...props}
                />
            )}
        </AppContext.Consumer>
    );
}

export default SelectCompanyTruck;
person Gustav.Calder    schedule 13.03.2019