Flux: Actions and the Dispatcher

July 30, 2014 by Bill Fisher


Flux is the application architecture Facebook uses to build JavaScript applications. It's based on a unidirectional data flow. We've built everything from small widgets to huge applications with Flux, and it's handled everything we've thrown at it. Because we've found it to be a great way to structure our code, we're excited to share it with the open source community. Jing Chen presented Flux at the F8 conference, and since that time we've seen a lot of interest in it. We've also published an overview of Flux and a TodoMVC example, with an accompanying tutorial.

Flux is more of a pattern than a full-blown framework, and you can start using it without a lot of new code beyond React. Up until recently, however, we haven't released one crucial piece of our Flux software: the dispatcher. But along with the creation of the new Flux code repository and Flux website, we've now open sourced the same dispatcher we use in our production applications.

Where the Dispatcher Fits in the Flux Data Flow #

The dispatcher is a singleton, and operates as the central hub of data flow in a Flux application. It is essentially a registry of callbacks, and can invoke these callbacks in order. Each store registers a callback with the dispatcher. When new data comes into the dispatcher, it then uses these callbacks to propagate that data to all of the stores. The process of invoking the callbacks is initiated through the dispatch() method, which takes a data payload object as its sole argument.

Actions and ActionCreators #

When new data enters the system, whether through a person interacting with the application or through a web api call, that data is packaged into an action — an object literal containing the new fields of data and a specific action type. We often create a library of helper methods called ActionCreators that not only create the action object, but also pass the action to the dispatcher.

Different actions are identified by a type attribute. When all of the stores receive the action, they typically use this attribute to determine if and how they should respond to it. In a Flux application, both stores and views control themselves; they are not acted upon by external objects. Actions flow into the stores through the callbacks they define and register, not through setter methods.

Letting the stores update themselves eliminates many entanglements typically found in MVC applications, where cascading updates between models can lead to unstable state and make accurate testing very difficult. The objects within a Flux application are highly decoupled, and adhere very strongly to the Law of Demeter, the principle that each object within a system should know as little as possible about the other objects in the system. This results in software that is more maintainable, adaptable, testable, and easier for new engineering team members to understand.

Why We Need a Dispatcher #

As an application grows, dependencies across different stores are a near certainty. Store A will inevitably need Store B to update itself first, so that Store A can know how to update itself. We need the dispatcher to be able to invoke the callback for Store B, and finish that callback, before moving forward with Store A. To declaratively assert this dependency, a store needs to be able to say to the dispatcher, "I need to wait for Store B to finish processing this action." The dispatcher provides this functionality through its waitFor() method.

The dispatch() method provides a simple, synchronous iteration through the callbacks, invoking each in turn. When waitFor() is encountered within one of the callbacks, execution of that callback stops and waitFor() provides us with a new iteration cycle over the dependencies. After the entire set of dependencies have been fulfilled, the original callback then continues to execute.

Further, the waitFor() method may be used in different ways for different actions, within the same store's callback. In one case, Store A might need to wait for Store B. But in another case, it might need to wait for Store C. Using waitFor() within the code block that is specific to an action allows us to have fine-grained control of these dependencies.

Problems arise, however, if we have circular dependencies. That is, if Store A needs to wait for Store B, and Store B needs to wait for Store A, we could wind up in an endless loop. The dispatcher now available in the Flux repo protects against this by throwing an informative error to alert the developer that this problem has occurred. The developer can then create a third store and resolve the circular dependency.

Example Chat App #

Along with the same dispatcher that Facebook uses in its production applications, we've also published a new example chat app, slightly more complicated than the simplistic TodoMVC, so that engineers can better understand how Flux solves problems like dependencies between stores and calls to a web API.

We're hopeful that the new Flux repository will grow with time to include additional tools, boilerplate code and further examples. And we hope that Flux will prove as useful to you as it has to us. Enjoy!

Community Round-up #20

July 28, 2014 by Lou Husson


It's an exciting time for React as there are now more commits from open source contributors than from Facebook engineers! Keep up the good work :)

Atom moves to React #

Atom, GitHub's code editor, is now using React to build the editing experience. They made the move in order to improve performance. By default, React helped them eliminate unnecessary reflows, enabling them to focus on architecting the rendering pipeline in order to minimize repaints by using hardware acceleration. This is a testament to the fact that React's architecture is perfect for high performant applications.

Why Does React Scale? #

At the last JSConf.us, Vjeux talked about the design decisions made in the API that allows it to scale to a large number of developers. If you don't have 20 minutes, take a look at the annotated slides.

Live Editing #

One of the best features of React is that it provides the foundations to implement concepts that were otherwise extremely difficult, like server-side rendering, undo-redo, rendering to non-DOM environments like canvas... Dan Abramov got hot code reloading working with webpack in order to live edit a React project!

ReactIntl Mixin by Yahoo #

There are a couple of React-related projects that recently appeared on Yahoo's GitHub, the first one being an internationalization mixin. It's great to see them getting excited about React and contributing back to the community.

var MyComponent = React.createClass({
  mixins: [ReactIntlMixin],
  render: function() {
    return (
      <div>
        <p>{this.intlDate(1390518044403, { hour: 'numeric', minute: 'numeric' })}</p>
        <p>{this.intlNumber(400, { style: 'percent' })}</p>
      </div>
    );
  }
});

React.renderComponent(
  <MyComponent locales={['fr-FR']} />,
  document.getElementById('example')
);

Thinking and Learning React #

Josephine Hall, working at Icelab, used React to write a mobile-focused application. She wrote a blog post “Thinking and Learning React.js” to share her experience with elements they had to use. You'll learn about routing, event dispatch, touchable components, and basic animations.

London React Meetup #

If you missed the last London React Meetup, the video is available, with lots of great content.

  • What's new in React 0.11 and how to improve performance by guaranteeing immutability
  • State handling in React with Morearty.JS
  • React on Rails - How to use React with Ruby on Rails to build isomorphic apps
  • Building an isomorphic, real-time to-do list with moped and node.js

In related news, the next React SF Meetup will be from Prezi: “Immediate Mode on the Web: How We Implemented the Prezi Viewer in JavaScript”. While not in React, their tech is really awesome and shares a lot of React's design principles and perf optimizations.

Using React and KendoUI Together #

One of the strengths of React is that it plays nicely with other libraries. Jim Cowart proved it by writing a tutorial that explains how to write React component adapters for KendoUI.

Acorn JSX #

Ingvar Stepanyan extended the Acorn JavaScript parser to support JSX. The result is a JSX parser that's 1.5–2.0x faster than the official JSX implementation. It is an experiment and is not meant to be used for serious things, but it's always a good thing to get competition on performance!

ReactScriptLoader #

Yariv Sadan created ReactScriptLoader to make it easier to write components that require an external script.

var Foo = React.createClass({
  mixins: [ReactScriptLoaderMixin],
  getScriptURL: function() {
    return 'http://d3js.org/d3.v3.min.js';
  },
  getInitialState: function() {
    return { scriptLoading: true, scriptLoadError: false };
  },
  onScriptLoaded: function() {
    this.setState({scriptLoading: false});
  },
  onScriptError: function() {
    this.setState({scriptLoading: false, scriptLoadError: true});
  },
  render: function() {
    var message =
      this.state.scriptLoading ? 'Loading script...' :
      this.state.scriptLoadError ? 'Loading failed' :
      'Loading succeeded';
    return <span>{message}</span>;
  }
});

Random Tweet #

React v0.11.1

July 25, 2014 by Paul O’Shannessy


Today we're releasing React v0.11.1 to address a few small issues. Thanks to everybody who has reported them as they've begun upgrading.

The first of these is the most major and resulted in a regression with the use of setState inside componentWillMount when using React on the server. These setState calls are batched into the initial render. A change we made to our batching code resulted in this path hitting DOM specific code when run server-side, in turn throwing an error as document is not defined.

There are several fixes we're including in v0.11.1 that are focused around the newly supported event.getModifierState() function. We made some adjustments to improve this cross-browser standardization.

The final fix we're including is to better support a workaround for some IE8 behavior. The edge-case bug we're fixing was also present in v0.9 and v0.10, so while it wasn't a short-term regression, we wanted to make sure we support IE8 to the best of our abilities.

We'd also like to call out a couple additional breaking changes that we failed to originally mention in the release notes for v0.11. We updated that blog post and the changelog, so we encourage you to go read about the changes around Descriptors and Prop Type Validation.

The release is available for download from the CDN:

We've also published version 0.11.1 of the react and react-tools packages on npm and the react package on bower.

Please try these builds out and file an issue on GitHub if you see anything awry.

Changelog #

React Core #

Bug Fixes #

  • setState can be called inside componentWillMount in non-DOM environments
  • SyntheticMouseEvent.getEventModifierState correctly renamed to getModifierState
  • getModifierState correctly returns a boolean
  • getModifierState is now correctly case sensitive
  • Empty Text node used in IE8 innerHTML workaround is now removed, fixing rerendering in certain cases

JSXTransformer #

  • Fix duplicate variable declaration (caused issues in some browsers)

React v0.11

July 17, 2014 by Paul O’Shannessy


Update: We missed a few important changes in our initial post and changelog. We've updated this post with details about Descriptors and Prop Type Validation.


We're really happy to announce the availability of React v0.11. There seems to be a lot of excitement already and we appreciate everybody who gave the release candidate a try over the weekend. We made a couple small changes in response to the feedback and issues filed. We enabled the destructuring assignment transform when using jsx --harmony, fixed a small regression with statics, and made sure we actually exposed the new API we said we were shipping: React.Children.count.

This version has been cooking for a couple months now and includes a wide array of bug fixes and features. We highlighted some of the most important changes below, along with the full changelog.

The release is available for download from the CDN:

We've also published version 0.11.0 of the react and react-tools packages on npm and the react package on bower.

Please try these builds out and file an issue on GitHub if you see anything awry.

getDefaultProps #

Starting in React 0.11, getDefaultProps() is called only once when React.createClass() is called, instead of each time a component is rendered. This means that getDefaultProps() can no longer vary its return value based on this.props and any objects will be shared across all instances. This change improves performance and will make it possible in the future to do PropTypes checks earlier in the rendering process, allowing us to give better error messages.

Rendering to null #

Since React's release, people have been using work arounds to "render nothing". Usually this means returning an empty <div/> or <span/>. Some people even got clever and started returning <noscript/> to avoid extraneous DOM nodes. We finally provided a "blessed" solution that allows developers to write meaningful code. Returning null is an explicit indication to React that you do not want anything rendered. Behind the scenes we make this work with a <noscript> element, though in the future we hope to not put anything in the document. In the mean time, <noscript> elements do not affect layout in any way, so you can feel safe using null today!

// Before
render: function() {
  if (!this.state.visible) {
    return <span/>;
  }
  // ...
}

// After
render: function() {
  if (!this.state.visible) {
    return null;
  }
  // ...
}

JSX Namespacing #

Another feature request we've been hearing for a long time is the ability to have namespaces in JSX. Given that JSX is just JavaScript, we didn't want to use XML namespacing. Instead we opted for a standard JS approach: object property access. Instead of assigning variables to access components stored in an object (such as a component library), you can now use the component directly as <Namespace.Component/>.

// Before
var UI = require('UI');
var UILayout = UI.Layout;
var UIButton = UI.Button;
var UILabel = UI.Label;

render: function() {
  return <UILayout><UIButton /><UILabel>text</UILabel></UILayout>;
}

// After
var UI = require('UI');

render: function() {
  return <UI.Layout><UI.Button /><UI.Label>text</UI.Label></UI.Layout>;
}

Improved keyboard event normalization #

Keyboard events now contain a normalized e.key value according to the DOM Level 3 Events spec, allowing you to write simpler key handling code that works in all browsers, such as:

handleKeyDown: function(e) {
  if (e.key === 'Enter') {
    // Handle enter key
  } else if (e.key === ' ') {
    // Handle spacebar
  } else if (e.key === 'ArrowLeft') {
    // Handle left arrow
  }
},

Keyboard and mouse events also now include a normalized e.getModifierState() that works consistently across browsers.

Descriptors #

In our v0.10 release notes, we called out that we were deprecating the existing behavior of the component function call (eg component = MyComponent(props, ...children) or component = <MyComponent prop={...}/>). Previously that would create an instance and React would modify that internally. You could store that reference and then call functions on it (eg component.setProps(...)). This no longer works. component in the above examples will be a descriptor and not an instance that can be operated on. The v0.10 release notes provide a complete example along with a migration path. The development builds also provided warnings if you called functions on descriptors.

Along with this change to descriptors, React.isValidComponent and React.PropTypes.component now actually validate that the value is a descriptor. Overwhelmingly, these functions are used to validate the value of MyComponent(), which as mentioned is now a descriptor, not a component instance. We opted to reduce code churn and make the migration to 0.11 as easy as possible. However, we realize this is has caused some confusion and we're working to make sure we are consistent with our terminology.

Prop Type Validation #

Previously React.PropTypes validation worked by simply logging to the console. Internally, each validator was responsible for doing this itself. Additionally, you could write a custom validator and the expectation was that you would also simply console.log your error message. Very shortly into the 0.11 cycle we changed this so that our validators return (not throw) an Error object. We then log the error.message property in a central place in ReactCompositeComponent. Overall the result is the same, but this provides a clearer intent in validation. In addition, to better transition into our descriptor factory changes, we also currently run prop type validation twice in development builds. As a result, custom validators doing their own logging result in duplicate messages. To update, simply return an Error with your message instead.

Changelog #

React Core #

Breaking Changes #

  • getDefaultProps() is now called once per class and shared across all instances
  • MyComponent() now returns a descriptor, not an instance
  • React.isValidComponent and React.PropTypes.component validate descriptors, not component instances.
  • Custom propType validators should return an Error instead of logging directly

New Features #

  • Rendering to null
  • Keyboard events include normalized e.key and e.getModifierState() properties
  • New normalized onBeforeInput event
  • React.Children.count has been added as a helper for counting the number of children

Bug Fixes #

  • Re-renders are batched in more cases
  • Events: e.view properly normalized
  • Added Support for more HTML attributes (coords, crossOrigin, download, hrefLang, mediaGroup, muted, scrolling, shape, srcSet, start, useMap)
  • Improved SVG support
    • Changing className on a mounted SVG component now works correctly
    • Added support for elements mask and tspan
    • Added support for attributes dx, dy, fillOpacity, fontFamily, fontSize, markerEnd, markerMid, markerStart, opacity, patternContentUnits, patternUnits, preserveAspectRatio, strokeDasharray, strokeOpacity
  • CSS property names with vendor prefixes (Webkit, ms, Moz, O) are now handled properly
  • Duplicate keys no longer cause a hard error; now a warning is logged (and only one of the children with the same key is shown)
  • img event listeners are now unbound properly, preventing the error "Two valid but unequal nodes with the same data-reactid"
  • Added explicit warning when missing polyfills

React With Addons #

  • PureRenderMixin: a mixin which helps optimize "pure" components
  • Perf: a new set of tools to help with performance analysis
  • Update: New $apply command to transform values
  • TransitionGroup bug fixes with null elements, Android

React NPM Module #

  • Now includes the pre-built packages under dist/.
  • envify is properly listed as a dependency instead of a peer dependency

JSX #

  • Added support for namespaces, eg <Components.Checkbox />
  • JSXTransformer
    • Enable the same harmony features available in the command line with <script type="text/jsx;harmony=true">
    • Scripts are downloaded in parallel for more speed. They are still executed in order (as you would expect with normal script tags)
    • Fixed a bug preventing sourcemaps from working in Firefox

React Tools Module #

  • Improved readme with usage and API information
  • Improved ES6 transforms available with --harmony option
  • Added --source-map-inline option to the jsx executable
  • New transformWithDetails API which gives access to the raw sourcemap data

React v0.11 RC

July 13, 2014 by Paul O’Shannessy


It's that time again… we're just about ready to ship a new React release! v0.11 includes a wide array of bug fixes and features. We highlighted some of the most important changes below, along with the full changelog.

The release candidate is available for download from the CDN:

We've also published version 0.11.0-rc1 of the react and react-tools packages on npm and the react package on bower.

Please try these builds out and file an issue on GitHub if you see anything awry.

getDefaultProps #

Starting in React 0.11, getDefaultProps() is called only once when React.createClass() is called, instead of each time a component is rendered. This means that getDefaultProps() can no longer vary its return value based on this.props and any objects will be shared across all instances. This change improves performance and will make it possible in the future to do PropTypes checks earlier in the rendering process, allowing us to give better error messages.

Rendering to null #

Since React's release, people have been using work arounds to "render nothing". Usually this means returning an empty <div/> or <span/>. Some people even got clever and started returning <noscript/> to avoid extraneous DOM nodes. We finally provided a "blessed" solution that allows developers to write meaningful code. Returning null is an explicit indication to React that you do not want anything rendered. Behind the scenes we make this work with a <noscript> element, though in the future we hope to not put anything in the document. In the mean time, <noscript> elements do not affect layout in any way, so you can feel safe using null today!

// Before
render: function() {
  if (!this.state.visible) {
    return <span/>;
  }
  // ...
}

// After
render: function() {
  if (!this.state.visible) {
    return null;
  }
  // ...
}

JSX Namespacing #

Another feature request we've been hearing for a long time is the ability to have namespaces in JSX. Given that JSX is just JavaScript, we didn't want to use XML namespacing. Instead we opted for a standard JS approach: object property access. Instead of assigning variables to access components stored in an object (such as a component library), you can now use the component directly as <Namespace.Component/>.

// Before
var UI = require('UI');
var UILayout = UI.Layout;
var UIButton = UI.Button;
var UILabel = UI.Label;

render: function() {
  return <UILayout><UIButton /><UILabel>text</UILabel></UILayout>;
}

// After
var UI = require('UI');

render: function() {
  return <UI.Layout><UI.Button /><UI.Label>text</UI.Label></UI.Layout>;
}

Improved keyboard event normalization #

Keyboard events now contain a normalized e.key value according to the DOM Level 3 Events spec, allowing you to write simpler key handling code that works in all browsers, such as:

handleKeyDown: function(e) {
  if (e.key === 'Enter') {
    // Handle enter key
  } else if (e.key === ' ') {
    // Handle spacebar
  } else if (e.key === 'ArrowLeft') {
    // Handle left arrow
  }
},

Keyboard and mouse events also now include a normalized e.getModifierState() that works consistently across browsers.

Changelog #

React Core #

Breaking Changes #

  • getDefaultProps() is now called once per class and shared across all instances

New Features #

  • Rendering to null
  • Keyboard events include normalized e.key and e.getModifierState() properties
  • New normalized onBeforeInput event
  • React.Children.count has been added as a helper for counting the number of children

Bug Fixes #

  • Re-renders are batched in more cases
  • Events: e.view properly normalized
  • Added Support for more HTML attributes (coords, crossOrigin, download, hrefLang, mediaGroup, muted, scrolling, shape, srcSet, start, useMap)
  • Improved SVG support
    • Changing className on a mounted SVG component now works correctly
    • Added support for elements mask and tspan
    • Added support for attributes dx, dy, fillOpacity, fontFamily, fontSize, markerEnd, markerMid, markerStart, opacity, patternContentUnits, patternUnits, preserveAspectRatio, strokeDasharray, strokeOpacity
  • CSS property names with vendor prefixes (Webkit, ms, Moz, O) are now handled properly
  • Duplicate keys no longer cause a hard error; now a warning is logged (and only one of the children with the same key is shown)
  • img event listeners are now unbound properly, preventing the error "Two valid but unequal nodes with the same data-reactid"
  • Added explicit warning when missing polyfills

React With Addons #

  • PureRenderMixin
  • Perf: a new set of tools to help with performance analysis
  • Update: New $apply command to transform values
  • TransitionGroup bug fixes with null elements, Android

React NPM Module #

  • Now includes the pre-built packages under dist/.
  • envify is properly listed as a dependency instead of a peer dependency

JSX #

  • Added support for namespaces, eg <Components.Checkbox />
  • JSXTransformer
    • Enable the same harmony features available in the command line with <script type="text/jsx;harmony=true">
    • Scripts are downloaded in parallel for more speed. They are still executed in order (as you would expect with normal script tags)
    • Fixed a bug preventing sourcemaps from working in Firefox

React Tools Module #

  • Improved readme with usage and API information
  • Improved ES6 transforms available with --harmony option
  • Added --source-map-inline option to the jsx executable
  • New transformWithDetails API which gives access to the raw sourcemap data