The correct way to throttle state-based HTTP calls in reduction and response

What I need: A managed component that is input[type="search"] . Say, 1 second without changing this component, I want to send an HTTP call to perform this search and show the results in another component.

How I did it: Whenever I call dispatch(setSearch(str)); I am making a dispatch(displaySearch(false)); call dispatch(displaySearch(false)); and then _.throttle call dispatch(displaySearch(true));

It seems to me that doing this kind of work in a component is wrong, but I can’t figure out how to do it in a reducer in redux.

+6
source share
2 answers

You have different options for solving this problem.

1. Give up on component level action

This is the easiest approach. When input triggers a change, it triggers a delayed version of setSearch delays the server call.

 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 with redux-saga

This approach requires more templates, but gives you much more control over your workflow. Using the saga, we intercept the SET_SEARCH action, cancel it, call the API, then submit a new action containing the results.

 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)) } 
+4
source

Bind delay and 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]; 
+1
source

All Articles