JSPM

  • Created
  • Published
  • Downloads 12093155
  • Score
    100M100P100Q208363F
  • License MIT

An experiment in fully hot-reloadable Flux

Package Exports

  • redux
  • redux/package.json

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (redux) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

redux

An experiment in fully hot-reloadable Flux.

The API might change any day.
Don't use in production.

Why another Flux framework?

Read The Evolution of Flux Frameworks for some context.

Design Goals

  • Hot reloading of everything.
  • A hook for the future devtools to "commit" a state, and replay actions on top of it during hot reload.
  • No createAction, createStores, wrapThisStuff. Your stuff is your stuff.
  • I don't mind action constants. Seriously.
  • Keep Flux lingo. No cursors or observables in core.
  • Have I mentioned hot reloading yet?

Demo

git clone https://github.com/gaearon/redux.git redux
cd redux
npm install
npm start

What's it look like?

Actions

// Still using constants...
import {
  INCREMENT_COUNTER,
  DECREMENT_COUNTER
} from '../constants/ActionTypes';

// But action creators are pure functions returning actions
export function increment() {
  return {
    type: INCREMENT_COUNTER
  };
}

export function decrement() {
  return {
    type: DECREMENT_COUNTER
  };
}

// Can also be async if you return a function
// (wow, much functions, so injectable :doge:)
export function incrementAsync() {
  return dispatch => {
    setTimeout(() => {
      dispatch(increment());
    }, 1000);
  };
}

// Could also look into state in the callback form
export function incrementIfOdd() {
  return (dispatch, state) => {
    if (state.counterStore.counter % 2 === 0) {
      return;
    }

    dispatch(increment());
  };
}

Stores

// ... too, use constants
import {
  INCREMENT_COUNTER,
  DECREMENT_COUNTER
} from '../constants/ActionTypes';

// but you can write this part anyhow you like:

const initialState = { counter: 0 };

function increment({ counter }) {
  return { counter: counter + 1 };
}

function decrement({ counter }) {
  return { counter: counter - 1 };
}

// what's important is that Store is a pure function too
export default function counterStore(state = initialState, action) {
  // that returns the new state when an action comes
  switch (action.type) {
  case INCREMENT_COUNTER:
    return increment(state, action);
  case DECREMENT_COUNTER:
    return decrement(state, action);
  default:
    return state;
  }
}

// bonus: no special support needed for ImmutableJS,
// just return its objects as the state.

Components

Dumb Components

// The dumb component receives everything using props:
import React, { PropTypes } from 'react';

export default class Counter {
  static propTypes = {
    counter: PropTypes.number.isRequired,
    increment: PropTypes.func.isRequired,
    decrement: PropTypes.func.isRequired
  };

  render() {
    const { counter } = this.props;
    return (
      <p>
        Clicked: {counter} times
      </p>
    );
  }
}

Smart Components

// The smart component may inject actions
// and observe stores using <Container />:

import React, { Component } from 'react';
import { Root, Container } from 'redux';
import { increment, decrement } from './actions/CounterActions';
import counterStore from './stores/counterStore';
import Counter from './Counter';

export default class CounterContainer {
  render() {
    // stores can be a single store or an array.
    // actions can only be a string -> function map.
    // props passed to children will combine these actions and state.
    return (
      <Container stores={counterStore}
                 actions={{ increment, decrement }}>
        {props => <Counter {...props} />}
      </Container>
    );
  }
}

The root component

import React from 'react';
import { Root } from 'redux';

@Root
export default class App {
  /* ... */
}

FAQ

How does hot reloading work?

Can I use this in production?

I wouldn't. Many use cases are not be considered yet. If you find some use cases this lib can't handle yet, please file an issue.