ForbesLindesay / redux-optimist

Optimistically apply actions that can be later commited or reverted.
MIT License
776 stars 39 forks source link

debounce? #8

Open amasad opened 8 years ago

amasad commented 8 years ago

What's the best way to debounce server requests? I have an editable text area that I want to do auto save on. The textareas' value is handled by redux but I don't want to overwhelm the server with updates on every keystroke. Any ideas?

ForbesLindesay commented 8 years ago

That's an interesting problem, and not one I've had to tackle yet personally. I think one option would be to always make your transaction ID something like the ID of the thing you are updating, then always fire a REVERT action before firing your begin transaction action. e.g.

import {BEGIN, COMMIT, REVERT} from 'redux-optimist';
import request from 'then-request';

const inProgress = {};
export default function (store) {
  return next => action => {
    if (action.type !== 'SET_VALUE') {
      return next(action);
    }
    const key = action.key;
    if (key in inProgress) {
      clearTimeout(inProgress[key]);
      next({
        type: 'PREPARE_DEBOUNCED_SET',
        optimist: {type: REVERT, id: key}
      });
    }
    next({
      ...action,
      optimist: {type: BEGIN, id: key}
    });
    inProgress[key] = setTimeout(() => {
      delete inProgress[key];
      request('POST', '/add_todo', {text: action.text}).getBody().done(
        res => next({
          ...action,
          type: 'SET_VALUE_COMPLETE',
          response: res,
          optimist: {type: COMMIT, id: key}
        }),
        err => next({
          ...action,
          type: 'SET_VALUE_FAILED',
          error: err,
          optimist: {type: REVERT, id: key}
        })
      );
    }, 1000);
  };
};

I haven't tested that, so I don't know for sure whether it works properly. It occurs to me that maybe we shouldn't have a special BEGIN type, and should just automatically BEGIN when you fire the first action with a given transactionID. That would allow you to remove the bit where you fire an action to revert the in-progress transaction.

amasad commented 8 years ago

Very briefly tried to implement this and it proved a bit tricky. I ended up keeping component local state and then debouncing the action dispatch at the component level. I may come back to this in the future though since it's nice to not have local state.