score:3

Associate 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];

score:9

You have different options to solve this.

1. Debounce your action at a component level

This is the simplest approach. When the input triggers a change, it calls a debounced version of setSearch delaying 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 using redux-saga

This approach requires more boilerplate but gives you a lot more control over the workflow. Using a saga we intercept the SET_SEARCH action, debounce it, call the API then dispatch 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))
}

Related Query

More Query from same tag