Atomic Flux with hot reloading
Atomic Flux with hot reloading.
The API is likely to change a few times before we reach 1.0.
Its surface area is minimal so you can try it in production and report any issues.
Read The Evolution of Flux Frameworks for some context.
git clone reduxcd reduxnpm installcd examples/todomvcnpm installnpm start
// Still using constants...import INCREMENT_COUNTER DECREMENT_COUNTER from '../constants/ActionTypes';// But action creators are pure functions returning actionsexportreturntype: INCREMENT_COUNTER;exportreturntype: DECREMENT_COUNTER;// Can also be async if you return a functionexportreturn dispatch =>setTimeout =>// Yay! Can invoke sync or async actions with `dispatch`dispatchincrement;1000;;// Could also read state of a store in the callback formexportreturn dispatch getState =>const counter = getState;if counter % 2 === 0return;dispatchincrement;;
// ... too, use constantsimport INCREMENT_COUNTER DECREMENT_COUNTER from '../constants/ActionTypes';// what's important is that Store is a pure function,// and you can write it anyhow you like.// the Store signature is (state, action) => state,// and the state shape is up to you: you can use primitives,// objects, arrays, or even ImmutableJS objects.export default// this function returns the new state when an action comesswitch actiontypecase INCREMENT_COUNTER:return state + 1;case DECREMENT_COUNTER:return state - 1;default:return state;// BUT THAT'S A SWITCH STATEMENT!// Right. If you hate 'em, see the FAQ below.
// The dumb component receives everything using props:import React PropTypes from 'react';export default class Counterstatic propTypes =increment: PropTypesfuncisRequireddecrement: PropTypesfuncisRequiredcounter: PropTypesnumberisRequired;renderconst increment decrement counter = thisprops;return<p>Clicked: counter times' '<button onClick=increment>+</button>' '<button onClick=decrement>-</button></p>;
// The smart component may observe stores using `<Connector />`,// and bind actions to the dispatcher with `bindActionCreators`.import React from 'react';import bindActionCreators from 'redux';import Connector from 'redux/react';import Counter from '../components/Counter';import * as CounterActions from '../actions/CounterActions';// You can optionally specify `select` for finer-grained subscriptions// and retrieval. Only when the return value is shallowly different,// will the child component be updated.return counter: statecounter ;export default class CounterApprenderreturn<Connector select=select>counter dispatch =>/* Yes this is child as a function. */<Counter counter=counterbindActionCreatorsCounterActions dispatch /></Connector>;
@connect decorator lets you create smart components less verbosely:
import React from 'react';import bindActionCreators from 'redux';import connect from 'redux/react';import Counter from '../components/Counter';import * as CounterActions from '../actions/CounterActions';@connectstate =>counter: statecounterexport default class CounterApprenderconst counter dispatch = thisprops;// Instead of `bindActionCreators`, you may also pass `dispatch` as a prop// to your component and call `dispatch(CounterActions.increment())`return<Counter counter=counterbindActionCreatorsCounterActions dispatch />;
To use Redux with React Native, just replace imports from
import bindActionCreators from 'redux';import Provider Connector from 'redux/react-native';
The simplest way to initialize a Redux instance is to give it an object whose values are your Store functions, and whose keys are their names. You may
import * from the file with all your Store definitions to obtain such an object:
import createRedux from 'redux';import Provider from 'redux/react';import * as stores from '../stores/index';const redux = createReduxstores;
redux as a prop to
<Provider> component in the root component of your app, and you're all set:
export default class Apprenderreturn<Provider redux=redux>=><CounterApp /></Provider>;
redux instance returned by
createRedux also has the
getState() methods that you may call outside the React components.
You may optionally specify the initial state as the second argument to
createRedux. This is useful for hydrating the state you received from running Redux on the server:
// serverconst redux = createReduxstores;reduxdispatchMyActionCreatorsdoSomething; // fire action creators to fill the stateconst state = reduxgetState; // somehow pass this state to the client// clientconst initialState = windowSTATE_FROM_SERVER;const redux = createReduxstores initialState;
There is also a longer way to do the same thing, if you need additional customization.
import createRedux from 'redux';import * as stores from '../stores/index';const redux = createReduxstores;
is in fact a shortcut for this:
import createRedux createDispatcher composeStores from 'redux';import thunkMiddleware from 'redux/lib/middleware/thunk';import * as stores from '../stores/index';// Compose all your Stores into a single Store function with `composeStores`:const store = composeStoresstores;// Create a Dispatcher function for your composite Store:const dispatcher = createDispatcherstoregetState => thunkMiddlewaregetState // Pass the default middleware;// Create a Redux instance using the dispatcher function:const redux = createReduxdispatcher;
Why would you want to write it longer? Maybe you're an advanced user and want to provide a custom Dispatcher function, or maybe you have a different idea of how to compose your Stores (or you're satisfied with a single Store). Redux lets you do all of this.
createDispatcher() also gives you the ability to specify middleware -- for example, to add support for promises. Learn more about how to create and use middleware in Redux.
When in doubt, use the shorter option!
Besides the examples in this repo, there is an officially supported example (still WIP) tackling those implementations.
Yep. People already do that although I warned them! The API surface is minimal so migrating to 1.0 API when it comes out won't be difficult. Let us know about any issues.
There's already a built-in way of doing async action creators:
// Can also be async if you return a functionexportreturn dispatch =>setTimeout =>// Yay! Can invoke sync or async actions with `dispatch`dispatchincrement;1000;;
It's also easy to implement support for returning Promises or Observables with a custom middleware. See an example of a custom Promise middleware.
(state, action) => state is as simple as a Store can get. You are free to implement your own
export defaultreturn state = initialState action =>handlersactiontype ?handlersactiontypestate action :state;
and use it for your Stores:
export default createStore0INCREMENT_COUNTER: x => x + 1DECREMENT_COUNTER: x => x - 1;
It's all just functions. Fancy stuff like generating stores from handler maps, or generating action creator constants, should be in userland. Redux has no opinion on how you do this in your project.
See also this gist for an example implementation of action constant generation.
I wrote a lot of vanilla Flux code and my only use case for it was to avoid emitting a change before a related Store consumes the action. This doesn't matter in Redux because the change is only emitted after all Stores have consumed the action.
If several of your Stores want to read data from each other and depend on each other, it's a sign that they should've been a single Store instead. See this discussion on how
waitFor can be replaced by the composition of stateless Stores.
Redux makes a hard assumption that you never mutate the state passed to you. It's easy! For example, instead of
stateisAuthenticated = true;stateemail = actionemail;return state;
you should write
returnstateisAuthenticated: trueemail: actionemail;
Read more about the spread properties ES7 proposal.
Action creators are just pure functions so they don't interact with anything. Components need to call
dispatch(action) (or use
bindActionCreators that wraps it) to dispatch an action returned by the action creator.
Stores are just pure functions too so they don't need to be “registered” in the traditional sense, and you can't subscribe to them directly. They're just descriptions of how data transforms. So in that sense they don't “interact” with anything either, they just exist, and are used by the dispatcher for computation of the next state.
Now, the dispatcher is more interesting. You pass all the Stores to it, and it composes them into a single Store function that it uses for computation. The dispatcher is also a pure function, and it is passed as configuration to
createRedux, the only stateful thing in Redux. By default, the default dispatcher is used, so if you call
createRedux(stores), it is created implicitly.
To sum it up: there is a Redux instance at the root of your app. It binds everything together. It accepts a dispatcher (which itself accepts Stores), it holds the state, and it knows how to turn actions into state updates. Everything else (components, for example) subscribes to the Redux instance. If something wants to dispatch an action, they need to do it on the Redux instance.
Connector is a handy shortcut for subscribing to a slice of the Redux instance's state and injecting
dispatch into your components, but you don't have to use it.
There is no other “interaction” in Redux.
Join the #redux channel of the Reactiflux Slack community
Special thanks go to Jamie Paton for handing over the
redux NPM package name.