AU Flux
Building complicated, intaractive UI applications is hard. Flux is the application architecture that Facebook uses for building these types of applications on the web. There are many different implementations of the Flux architecture, but I found them difficult to wrap my head around. AU Flux is a simplified implementation of a Flux architecture with a few basic additions to make development more fun and more efficient.
A simple react component...
Let's start with a simple react component. A button:
;; Component { return <div> <button>0 Likes</button> </div> ; } ReactDOM;
We'd like to have this button count up from zero as it's clicked on. In React we might commonly do that by updating the state on each click like so:
;; Component // Set the initial state { superprops; thisstate = numLikes: 0 ; } { // On each click increment the state by one return <div> <button onClick= this> thisstatenumLikes Likes </button> </div> ; } ReactDOM;
Managing more complex data...
This is great, but what if we want to also store the number of likes in a database on our server? Maybe we'd also like to allow other components in our web app to display the number of likes (accurately). As complexity grows, this approach to storing data can become very cumbersome. Flux architecture prescribes what should happen when an action occurs within our UI (like clicking on a button). The general flow of information looks like this:
Image taken from Fluxxor - What is Flux?
Within AU Flux we can follow this pattern by first creating a store. Aptly named because it's a place to store our data. In this particular example, the number of likes. Here's an example of what the store might look like:
;;; // Import the store builder Component { superprops; thisstate = numLikes: 0 ; } { return <div> <button onClick= this> thisstatenumLikes Likes </button> </div> ; } // Create a new store that will respond to the 'add_like' actionconst LikeCount = Store; // Instantiate the store that we defined above and set it's initial value to 0.const likeCount = 0;
Each AU Flux store is created using Store.build(...)
and passed an object. The property names of that object represent actions that may occur in your app (in this case "add_like"). The value of each property should be an async function to handle the action (or an object with an async run
method to handle the action). The handler always takes one action
argument and should return the new state of the store or throw an error. In this case we are just grabbing the current value of the store and adding one to it.
Connecting the pieces
Now that we have created our first store all we need to do is inform our app about it and call the add_like
action.
;;; // Import au-flux globals Component { superprops; thisstate = numLikes: 0 ; } { return <div> <button onClick= this> thisstatenumLikes Likes </button> </div> ; } const LikeCount = Store; const likeCount = 0; // Create a list of all of the stores that our app is using. If we had multiple stores in our app we// would list all of them hereconst stores = likeCount // Notify au-flux about those stores so that they can be usedglobals; ReactDOM;
What we've done here is a little bit of connecting work. AU Flux needs to keep track of all of the stores in our application, and it does that in the globals object. We import the globals object, create a new stores object to keep track of all of the stores (in this case there is only one) and set the 'stores' global.
We're almost there, just one more change. Instead of updating the state in our button we want to update our store. Instead of reading from the button state we want to read from the store state:
;;// SmartComponents allow us to connect our store to generic React components. `d` is the default// dispatcher which we can use to dispatch actions.; Component { // Use props instead of state. The props are passed from the SmartButton. // d.trigger dispatches a new action when the button is clicked. return <div> <button onClick= d> thispropslikeCount Likes </button> </div> ; } // This creates a wrapper component that passes the store to the Button component via props.const SmartButton = SmartComponent; const LikeCount = Store; const likeCount = 0; const stores = likeCount; globals; // Use the SmartButton instead of the regular button now.ReactDOM;