Skip to content

Commit c141f0a

Browse files
committed
Merge pull request #119 from colindresj/jc-docs
Updates to getting started docs
2 parents d8ec961 + b7d6ed5 commit c141f0a

8 files changed

+348
-260
lines changed

docs/src/components/nav.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default React.createClass({
1717
{logo}
1818
<ul id="nav-mobile" className="right hide-on-med-and-down">
1919
<li><a href={urlize("docs/01-getting-started.html")}>Docs</a></li>
20-
<li><a href={urlize("docs/05-api.html")}>API</a></li>
20+
<li><a href={urlize("docs/07-api.html")}>API</a></li>
2121
<li><a href="https://github.com/optimizely/nuclear-js">Github</a></li>
2222
</ul>
2323
</div>

docs/src/docs/01-getting-started.md

+22-258
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ section: "Guide"
55

66
# Getting Started
77

8-
This guide will take you through the process of install NuclearJS and familiarize you with the concepts found in Nuclear to build Flux systems.
8+
This guide will take you through the process of installing NuclearJS and familiarize you with the concepts that will allow you
9+
to build Flux systems.
910

1011
## Installation
1112

@@ -16,34 +17,42 @@ npm install --save nuclear-js
1617

1718
## Overview
1819

19-
In this tutorial we will create a Nuclear flux system to show a list of products and add them to a shopping cart. Here's the plan:
20+
In this tutorial we'll create a Nuclear flux system to show a list of products and add them to a shopping cart. Here's the plan:
2021

2122
1. Create a **Reactor**
2223

23-
2. Create **actions** to fetch products from a server and to add a product to the shopping cart
24+
2. Create **Actions** to fetch products from a server and to add a product to the shopping cart
2425

2526
3. Create a **ProductStore** and **ShoppingCartStore**
2627

27-
4. Create **getters** to transform and compose our store data into a consumable format for the UI
28+
4. Create **Getters** to transform and compose our store data into a consumable format for the UI
2829

2930
5. Hook everything up to React
3031

3132
### A few things to do know before we start
3233

33-
1. Although the example code is written using ES6, this is totally optional. NuclearJS fully supports ES5 out of the box
34+
1. Although the example code is written using ES6, this is totally optional. NuclearJS fully supports ES5 out of the box.
3435

3536
2. Nuclear stores work best when using ImmutableJS data structures. You will see `toImmutable` quite often, this is simply sugar
36-
to convert plain javascript arrays into [`Immutable.List`](http://facebook.github.io/immutable-js/docs/#/List) and objects to
37+
to convert plain JavaScript arrays into [`Immutable.List`](http://facebook.github.io/immutable-js/docs/#/List) and objects to
3738
[`Immutable.Map`](http://facebook.github.io/immutable-js/docs/#/Map). The use of `toImmutable` is optional, you are free to use
3839
any ImmutableJS data structure with no penalty.
3940

4041

4142
## Creating a `Reactor`
4243

43-
In Nuclear the `Reactor` is the brains of the system. Generally you will only have one reactor for your application, however they are instanceable
44-
for server-side rendering.
44+
To get started, we'll create a Nuclear `Reactor`. In Nuclear, the `Reactor` is the brains of the system and in some ways analogous
45+
to the traditional Flux `dispatcher` (though it works differently under the hood and provides a few extra features, which we'll
46+
cover later).
4547

46-
The reactor holds the application state in the form of an `Immutable.Map`, while dispatching actions transform the application state.
48+
Generally you'll only have one reactor for your application, however they are instanceable for server-side rendering.
49+
50+
The reactor has two main jobs:
51+
52+
1. It holds the entire application state in the form of an `Immutable.Map`
53+
2. It dispatches actions to transform the application state
54+
55+
Let's begin by creating a `reactor.js` file.
4756

4857
#### `reactor.js`
4958

@@ -57,254 +66,9 @@ const reactor = new Reactor({
5766
export default reactor
5867
```
5968

69+
_* If you pass a `debug: true` option when instantiating a reactor, you'll get great debugging tools that print to your browser console.
70+
This is completely optional, but very useful for keeping tracking of dispatched actions and subsequest changes in state._
6071

61-
## Actions
62-
63-
Actions are categorized as any function that calls `reactor.dispatch(actionType, payload)`.
64-
65-
For our example we will start by creating actions to fetch products from a server and to add a product to the users shopping cart.
66-
67-
#### `actionTypes.js`
68-
69-
```javascript
70-
import keyMirror from 'react/lib/keyMirror'
71-
72-
export default keyMirror({
73-
RECEIVE_PRODUCTS: null,
74-
ADD_TO_CART: null,
75-
CHECKOUT_START: null,
76-
CHECKOUT_SUCCESS: null,
77-
CHECKOUT_FAILED: null,
78-
})
79-
```
80-
81-
#### `actions.js`
82-
83-
```javascript
84-
import shop from '../../common/api/shop'
85-
import reactor from './reactor'
86-
import {
87-
RECEIVE_PRODUCTS,
88-
ADD_TO_CART,
89-
CHECKOUT_START,
90-
CHECKOUT_SUCCESS,
91-
CHECKOUT_FAILED,
92-
} from './actionTypes'
93-
94-
export default {
95-
fetchProducts() {
96-
shop.getProducts(products => {
97-
reactor.dispatch(RECEIVE_PRODUCTS, { products })
98-
});
99-
},
100-
101-
addToCart(product) {
102-
reactor.dispatch(ADD_TO_CART, { product })
103-
},
104-
}
105-
```
106-
107-
108-
## Creating Stores
109-
110-
Stores hold no state, instead they provide a collection of functions that transform current state into new state. They provide an `initialize` hook used when
111-
registering with a reactor to define what actions they respond to.
112-
113-
In Nuclear there is no need to worry about stores knowing about other stores or `store.waitsFor`. The sole responsibility of stores is to write or mutate application
114-
state, and the responsibility of reading application state falls on Getters.
115-
116-
117-
#### `stores/ProductStore.js`
118-
119-
```javascript
120-
import { Store, toImmutable } from 'nuclear-js'
121-
import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../actionTypes'
122-
123-
// example product:
124-
// {{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2, "image": "../common/assets/ipad-mini.png"},"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2, "image": "../common/assets/ipad-mini.png"},
125-
126-
export default Store({
127-
getInitialState() {
128-
return toImmutable({})
129-
},
130-
131-
initialize() {
132-
this.on(RECEIVE_PRODUCTS, receiveProducts)
133-
this.on(ADD_TO_CART, decrementInventory)
134-
}
135-
})
136-
137-
// store handlers transform `(currentState, payload) => (newState)`
138-
function receiveProducts(state, { products }) {
139-
// transform an array of products to a map keyed by product.id
140-
let newProducts = toImmutable(products)
141-
.toMap()
142-
.mapKeys((k, v) => v.get('id'))
143-
return state.merge(newProducts)
144-
}
145-
146-
function decrementInventory(state, { product }) {
147-
return state.update(product.id, product => {
148-
let currentInventory = product.get('inventory')
149-
let newInventory = (currentInventory > 0) ? currentInventory - 1 : 0;
150-
return product.set('inventory', newInventory)
151-
})
152-
}
153-
```
154-
155-
#### `stores/CartStore.js`
156-
157-
```javascript
158-
import { Store, toImmutable } from 'nuclear-js'
159-
import { ADD_TO_CART } from '../actionTypes'
160-
161-
const initialState = toImmutable({
162-
// mapping of product.id to quantity
163-
itemQty: {},
164-
})
165-
166-
/**
167-
* CartStores holds the mapping of productId => quantity
168-
* and also maintains rollback information for the checkout process
169-
*/
170-
export default Store({
171-
getInitialState() {
172-
return initialState
173-
},
174-
175-
initialize() {
176-
this.on(ADD_TO_CART, addToCart)
177-
}
178-
})
179-
180-
function addToCart(state, { product }) {
181-
let id = product.id
182-
return (state.hasIn(['itemQty', id]))
183-
? state.updateIn(['itemQty', id], quantity => quantity + 1)
184-
: state.setIn(['itemQty', id], 1)
185-
}
186-
```
187-
188-
### Registering our stores
189-
190-
Registering the store with a reactor does two things:
191-
192-
1. Passes every dispatched action to the store
193-
2. Binds a store's state to the application state by the key used for registration
194-
195-
#### `main.js`
196-
197-
```javascript
198-
import reactor from './reactor'
199-
import ProductStore from './stores/ProductStore'
200-
import CartStore from './stores/CartStore'
201-
202-
reactor.registerStores({
203-
'products': ProductStore,
204-
'cart': CartStore,
205-
})
206-
```
207-
208-
## Recap
209-
210-
At this point we've created actions for fetching products and adding an item to the cart. We also have the `ProductStore` and `CartStore` registered on the reactor.
211-
212-
Let's see what our application state looks like by using the `reactor.evaluate` function:
213-
214-
```javascript
215-
// providing an empty array to `evaluate` will return a snapshot of the entire app state
216-
reactor.evaluate([])
217-
// result
218-
Map {
219-
cart: Map {
220-
itemQty: Map {}
221-
},
222-
products: Map {}
223-
}
224-
225-
reactor.evaluate(['cart'])
226-
// result
227-
Map {
228-
itemQty: Map {}
229-
}
230-
```
231-
232-
The application state is rather empty, each top level key is populated by the store's `getInitialState()` method.
233-
234-
Let's see what our application state looks like after we fetch some products.
235-
236-
```javascript
237-
actions.fetchProducts()
238-
```
239-
240-
After the products have been fetched:
241-
242-
```javascript
243-
Map {
244-
cart: Map {
245-
itemQty: Map {}
246-
},
247-
products: Map {
248-
1: Map { id: 1, title: "iPad 4 Mini", price: 500.01, inventory: 2, image: "../common/assets/ipad-mini.png" },
249-
2: Map { id: 2, title: "H&M T-Shirt White", price: 10.99, inventory: 10, image: "../common/assets/t-shirt.png" },
250-
3: Map { id: 3, title: "Charli XCX - Sucker CD", price: 19.99, inventory: 5, image: "../common/assets/sucker.png" }
251-
}
252-
}
253-
```
254-
255-
Now let's add a product to our shopping cart:
256-
257-
```javascript
258-
actions.addToCart({ id: 3 })
259-
```
260-
261-
Notice there is an entry in the `itemQty` map as well as the inventory for **Charli XCX - Sucker CD** went from 5 to 4.
262-
263-
```javascript
264-
Map {
265-
cart: Map {
266-
itemQty: Map {
267-
3: 1
268-
}
269-
},
270-
products: Map {
271-
1: Map { id: 1, title: "iPad 4 Mini", price: 500.01, inventory: 2, image: "../common/assets/ipad-mini.png" },
272-
2: Map { id: 2, title: "H&M T-Shirt White", price: 10.99, inventory: 10, image: "../common/assets/t-shirt.png" },
273-
3: Map { id: 3, title: "Charli XCX - Sucker CD", price: 19.99, inventory: 4, image: "../common/assets/sucker.png" }
274-
}
275-
}
276-
```
277-
278-
The information in our stores are pretty minimal, the cart store doesn't actually know anything about the product, like its title, price or images -
279-
all information that we would need if we were to build a cart component.
280-
281-
Nuclear allows you to combine data from stores in a non-destructive manner, check it out:
282-
283-
```javascript
284-
reactor.evaluate([
285-
['cart', 'itemQty'],
286-
['products'],
287-
(itemQty, products) => {
288-
return itemQty.map((qty, itemId) => {
289-
return toImmutable({
290-
product: products.get(itemId),
291-
quantity: qty
292-
})
293-
}).toList()
294-
}
295-
])
296-
```
297-
298-
```javascript
299-
List [
300-
Map {
301-
product: Map { id: 3, title: "Charli XCX - Sucker CD", price: 19.99, inventory: 4, image: "../common/assets/sucker.png" },
302-
quantity: 1,
303-
}
304-
}
305-
```
306-
307-
You've just seen your first **Getter**, and just in time too! The next section is all about getters, one of the most powerful abstractions in Nuclear.
308-
309-
#### [Next: Getters](./02-getters.html)
72+
Now that we have our reactor, let's create some actions.
31073

74+
#### [Next: Creating Actions](./02-creating-actions.html)

docs/src/docs/02-creating-actions.md

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
title: "Creating Actions"
3+
section: "Guide"
4+
---
5+
6+
# Creating Actions
7+
8+
Actions (sometimes called action creators) are functions that you call to send data into the system. In Nuclear, any function that calls
9+
`reactor.dispatch(actionType: string, payload: any)` is categorized as an action.
10+
11+
For our example, we'll start by creating an action to fetch products from a server and another action to add a product to the user's shopping cart.
12+
13+
In order to correctly reference actions throughout the system, we'll create an `actionTypes.js` file, which is simply a collection of constants.
14+
We're using React's keyMirror utility to create the constants, but that's just a convenience — you can create action types in any way you'd like.
15+
They're not even required to be in a separate file, though that's certainly recommended.
16+
17+
#### `actionTypes.js`
18+
19+
```javascript
20+
import keyMirror from 'react/lib/keyMirror'
21+
22+
export default keyMirror({
23+
RECEIVE_PRODUCTS: null,
24+
ADD_TO_CART: null,
25+
CHECKOUT_START: null,
26+
CHECKOUT_SUCCESS: null,
27+
CHECKOUT_FAILED: null,
28+
})
29+
```
30+
31+
#### `actions.js`
32+
33+
```javascript
34+
import shop from '../../common/api/shop'
35+
import reactor from './reactor'
36+
import {
37+
RECEIVE_PRODUCTS,
38+
ADD_TO_CART,
39+
CHECKOUT_START,
40+
CHECKOUT_SUCCESS,
41+
CHECKOUT_FAILED,
42+
} from './actionTypes'
43+
44+
export default {
45+
fetchProducts() {
46+
shop.getProducts(products => {
47+
reactor.dispatch(RECEIVE_PRODUCTS, { products })
48+
});
49+
},
50+
51+
addToCart(product) {
52+
reactor.dispatch(ADD_TO_CART, { product })
53+
},
54+
}
55+
```
56+
57+
We've now created two actions that we can use to send data into the system.
58+
59+
`addToCart` is a simple, synchronous action that takes in a product and dispatches `"ADD_TO_CART"` with the product in the payload.
60+
61+
While synchronous actions are great, often you'll need to perform an asynchronous operation before dispatching an action. Nuclear
62+
fully supports creating actions asynchronously, as we're doing in `fetchProducts`. This is a common pattern you'll use as your application grows,
63+
and Nuclear has no opinion on how you perform your operations: callbacks, Promises, Generators, ES7 async functions — they'll all work just fine!
64+
65+
If you'd like to jump ahead, you can read more about [async actions](./04-async-actions-and-optimistic-updates.html).
66+
67+
Now let's build a few stores.
68+
69+
#### [Next: Creating Stores](./03-creating-stores.html)

0 commit comments

Comments
 (0)