2016-04-13 18 views
6

Was ich brauche: Ein controlled component, die ein input[type="search"] ist. Nach sagen, 1 Sekunde ohne Änderungen an dieser Komponente möchte ich einen HTTP-Aufruf senden, um diese Suche auszuführen und die Ergebnisse in einer anderen Komponente angezeigt zu bekommen.korrekte Art und Weise HTTP Anrufe basierend auf Zustand in redux zu drosseln und reagieren

Wie ich habe es getan: Immer, wenn ich dispatch(setSearch(str)); nenne ich einen Anruf zu dispatch(displaySearch(false)); mache und dann _.throttle einen Aufruf an dispatch(displaySearch(true));

Es mir die Ansicht, dass in der Komponente, diese Art von Arbeit zu tun ist falsch , aber ich kann mir keinen Weg vorstellen, dies in Reducer zu reduzieren.

+0

Wollen Sie some global für alle Ihre Anwendung (wie für alle API-Aufrufe) oder nur für diese Komponente? – KeitIG

+0

Ich konnte sehen, dass es in anderen Komponenten in diesem Abschnitt der Anwendung verwendet wird. – Dave

+0

siehe http://stackoverflow.com/questions/23123138/perform-debounce-in-react-js/28046731#28046731 –

Antwort

4

Sie haben verschiedene Möglichkeiten, dies zu lösen.

1. Debounce Ihre Aktion auf Komponentenebene

Dies ist der einfachste Ansatz. Wenn der Eingang eine Änderung auslöst, ruft er eine entprellte Version setSearch auf, die den Serveraufruf verzögert.

import * as React from "react" 
import {connect} from "react-redux" 
import {setSearch} from "./actions" 

export default connect(
    null, 
    function mapDispatchToProps(dispatch) { 
    const setSearch_ = _.debounce(q => dispatch(setSearch(q)), 1000) 
    return() => ({setSearch: setSearch_}) 
    } 
)(
    function SearchForm(props) { 
    const {setSearch} = props 
    return (
     <input type="search" onChange={setSearch} /> 
    ) 
    } 
) 

2. Debounce redux-saga

Dieser Ansatz erfordert mehr vorformulierten sondern gibt Ihnen viel mehr Kontrolle über der Workflow. Mit einer Saga fangen wir die SET_SEARCH Aktion ab, debunce es, rufen Sie die API, dann senden Sie eine neue Aktion, die die Ergebnisse enthält.

import {call, cancel, fork, put, take} from "redux-saga/effects" 
import {setSearchResults} from "./actions" 
import {api} from "./services" 
import {delay} from "./utils" 

export default function* searchSaga() { 
    yield [ 
    // Start a watcher to handle search workflow 
    fork(watchSearch) 
    ] 
} 

function* watchSearch() { 
    let task 

    // Start a worker listening for `SET_SEARCH` actions. 
    while (true) { 
    // Read the query from the action 
    const {q} = yield take("SET_SEARCH") 

    // If there is any pending search task then cancel it 
    if (task) { 
     yield cancel(task) 
    } 

    // Create a worker to proceed search 
    task = yield fork(handleSearch, q) 
    } 
} 

function* handleSearch(q) { 
    // Debounce by 1s. This will lock the process for one second before 
    // performing its logic. Since the process is blocked, it can be cancelled 
    // by `watchSearch` if there are any other actions. 
    yield call(delay, 1000) 

    // This is basically `api.doSearch(q)`. The call should return a `Promise` 
    // that will resolve the server response. 
    const results = yield call(api.doSearch, q) 

    // Dispatch an action to notify the UI 
    yield put(setSearchResults(results)) 
} 
+1

Schlechte Idee: das Entprellen der Funktion auf 'mapDispatchToProps' bedeutet, dass die entprellte Funktion jedes Mal neu erstellt wird Änderungen, was bedeutet, dass es nicht entlarvt wird. Auch für Redux-Saga gibt es ein Dokument auf dem: http://yelouafi.github.io/redux-saga/docs/recipes/index.html –

+0

@SebastienLorber Sie hatten Recht über 'mapDispatchToProps'. Ich habe meine Antwort aktualisiert, es ist nicht mehr der Fall, danke! Und ja, mein Beispielcode wurde den Rezepten von Redux Saga entlehnt. – Florent

1

Mitarbeiterin delay und takeLatest:

import { all, takeLatest, call } from 'redux-saga/effects'; 
import { delay } from 'redux-saga'; 


function* onSearch(action) { 
    yield call(delay, 1000); // blocks until a new action is 
          // triggered (takeLatest) or until 
          // the delay of 1s is over 

    const results = yield call(myFunction); 
} 

function* searchSagas() { 
    yield all([ 
    // ... 
    takeLatest(ON_SEARCH, onSearch), 
    ]); 
} 

export default [searchSagas]; 
Verwandte Themen