Coder Social home page Coder Social logo

redux's Introduction

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.
  • Embrace decorators for React components.
  • 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 incremenent({ counter }) {
  return { counter: counter + 1 };
}

function decremenent({ 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 incremenent(state, action);
  case DECREMENT_COUNTER:
    return decremenent(state, action);
  default:
    return state;
  }
}

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

Components

Observing a single Store

// We're gonna need some decorators
import React from 'react';
import { observes } from 'redux';

// Gonna subscribe it
@observes('counterStore')
export default class Counter {
  render() {
    const { counter } = this.props; // injected by @observes
    return (
      <p>
        Clicked: {counter} times
      </p>
    );
  }
}

Observing many Stores

// We're gonna need some decorators
import React from 'react';
import { observes } from 'redux';

// With multiple stores, you might want to specify a prop mapper as last argument.
// You can also access `props` inside the prop mapper.
@observes('counterStore', 'todoStore', (state, props) => ({
  counter: state.counterStore.counter,
  todos: state.todoStore.todos
}))
export default class TodosWithCounter {
  /* ... */
}

Performing a single Action

// We're gonna need some decorators
import React from 'react';
import { performs } from 'redux';

// Gonna inject it
@performs('increment')
export default class IncrementButton {
  render() {
    const { increment } = this.props; // injected by @performs
    return (
      <button onClick={increment}>+</button>
    );
  }
}

Performing many Actions

// We're gonna need some decorators
import React from 'react';
import { performs } from 'redux';

// With multiple actions, you might want to specify a prop mapper as last argument.
// You can also access `props` inside the prop mapper.
@performs('increment', 'decrement', (actions, props) => ({
  increment: props.invert ? actions.decrement : actions.increment,
  decrement: props.invert ? actions.increment : actions.decrement
}))
export default class IncrementButton {
  /* .... */
}

Dispatcher

Creating a hot-reloadable dispatcher

import * as stores from './stores/index';
import * as actions from './actions/index';
import { createDispatcher } from 'redux';

// Prefer to use existing dispatcher
const dispatcher =
  module.hot && module.hot.data && module.hot.data.dispatcher ||
  createDispatcher();

// Pass (potentially hot-reloaded) stores and actions
dispatcher.receive(stores, actions);

// Store the dispatcher for the next hot reload
if (module.hot) {
  module.hot.dispose(data => {
    data.dispatcher = dispatcher;
  });
}

export default dispatcher;

Attaching the dispatcher to the root component

import React from 'react';
import { provides } from 'redux';
import dispatcher from './dispatcher';

@provides(dispatcher)
export default class App {
  /* ... */
}

FAQ

How does hot reloading work?

But you're using strings for injecting actions and store state!

I'm not super happy about strings. If you find a better way, let me know and file an issue with your suggestions.

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.

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.