Coder Social home page Coder Social logo

redux-optimistic-ui's Introduction

npm version Build Status Coverage Status

redux-optimistic-ui

a reducer enhancer to enable type-agnostic optimistic updates

##Installation npm i -S redux-optimistic-ui

A what-now?

A reducer enhance is a function you put around a reducer. It can be your rootReducer (the output from a combineReducers) or a nested one. Optimistic-UI means you update what the client sees before the result comes back from the server. This makes your app feel super fast, regardless of server location or internet connection speed.

How's it different from redux-optimist?

redux-optimistic-ui redux-optimist
reducerEnhancer (wraps your state in an immutable Map) reducerExtender (adds an optimist to your state)
can use immutable.js or anything else must use plain JS objects for your state
only uses 1 state copy saves an extra copy of your state for every new optimistic action
uses immutable.js behind the scenes uses native JS objects behind the scenes
FSA compliant not FSA compliant
must wrap your state calls in ensureState no change necessary to get your state
##Usage

###Feed it your reducer

import {optimistic} from 'redux-optimistic-ui';
return optimistic(reducer);

This will transform your state so it looks like this:

state = Map({
  history: List(),
  beforeState: <YOUR PREVIOUS STATE HERE>
  current: <YOUR STATE HERE>
})

If the client is not waiting for a response from the server, the following are guaranteed to be true:

  • state.get('history').size === 0
  • state.get('beforeState') === undefined

If you don't need to know if there is an outstanding fetch, you'll never need to use these.

###Update your references to state

Since your state is now wrapped, you need state.get('current'). But that sucks. What if you don't enhance the state until the user hits a certain route? Lucky you! There's a function for that. ensureState will give you your state whether it's enhanced or not. Just wrap all your references to state and getState with it & you're all set!

// Before
getState().counter

// After (whether you've enhanced your reducer or not)
import {ensureState} from 'redux-optimistic-ui'
ensureState(getState()).counter

###Write some middleware

Now comes the fun! Not all of your actions should be optimistic. Just the ones that fetch something from a server and have a high probability of success. I like real-world examples, so this middleware is a little bit longer than the bare requirements:

import {BEGIN, COMMIT, REVERT} from 'redux-optimistic-ui';

//All my redux action types that are optimistic have the following suffixes, yours may vary
const _SUCCESS = '_SUCCESS';
const _ERROR = '_ERROR';

//Each optimistic item will need a transaction Id to internally match the BEGIN to the COMMIT/REVERT 
let nextTransactionID = 0;

// That crazy redux middleware that's 3 functions deep!
export default store => next => action => {
  // FSA compliant
  const {type, meta, payload} = action;
  
  // For actions that have a high probability of failing, I don't set the flag
  if (!meta || !meta.isOptimistic) return next(action);

  // Now that we know we're optimistically updating the item, give it an ID
  let transactionID = nextTransactionID++;

  // Extend the action.meta to let it know we're beginning an optimistic update
  next(Object.assign({}, action, {meta: {optimistic: {type: BEGIN, id: transactionID}}}));

  // HTTP is boring, I like sending data over sockets, the 3rd arg is a callback 
  socket.emit(type, payload, error => {
    // Create a redux action based on the result of the callback 
    next({
      type: type + (error ? _ERROR : _SUCCESS),
      error,
      payload,
      meta: {
        //Here's the magic: if there was an error, revert the state, otherwise, commit it
        optimistic: error ? {type: REVERT, id: transactionID} : {type: COMMIT, id: transactionID}
      }
    });
  })
};

##Pro tips Not using an optimistic-ui until a certain route? Using something like redux-undo in other parts? Write a little something like this and call it on your asychronous route:

export default (newReducers, reducerEnhancers) => {
  Object.assign(currentReducers, newReducers);
  const reducer = combineReducers({...currentReducers})
  if (reducerEnhancers){
    return Array.isArray(reducerEnhancers) ? compose(...reducerEnhancers)(reducer) : reducerEnhancers(reducer);
  }
  return reducer;
}

Now you get an enhanced reducer only where you want it. Neat.

To see how it all comes together, check out https://github.com/mattkrick/meatier.

redux-optimistic-ui's People

Contributors

mattkrick avatar cdock1029 avatar raitobezarius avatar

Stargazers

Cody Olsen avatar

Watchers

James Cloos avatar Andy Edwards avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.