Skip to content

Commit 4481d2b

Browse files
committed
Docs: add async actions and optimistic updates section
1 parent aed09b0 commit 4481d2b

File tree

4 files changed

+162
-5
lines changed

4 files changed

+162
-5
lines changed

docs/sass/components/_typography.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ h6 { font-size: $h6-fontsize; line-height: 1.1*$h6-fontsize; margin: ($h6-fontsi
3636

3737
// Text Styles
3838
em { font-style: italic; }
39-
strong { font-weight: 500; }
4039
small { font-size: 75%; }
4140
.light { font-weight: 300; }
4241
.thin { font-weight: 200; }

docs/sass/components/_variables.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ $off-black: rgba(0, 0, 0, 0.87) !default;
120120
$h1-fontsize: 2.92rem !default;
121121
$h2-fontsize: 2.28rem !default;
122122
$h3-fontsize: 1.64rem !default;
123-
$h4-fontsize: 1rem !default;
124-
$h5-fontsize: 1rem !default;
123+
$h4-fontsize: 1.32rem !default;
124+
$h5-fontsize: 1.1rem !default;
125125
$h6-fontsize: 1rem !default;
126126

127127
// Footer

docs/src/docs/05-hooking-up-to-react.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ import actions from '../actions'
107107

108108
const ProductItemContainer = React.createClass({
109109
onAddToCartClicked() {
110-
// we will implement this in the next section
110+
actions.addToCart(this.props.product)
111111
},
112112

113113
render() {

docs/src/docs/06-async-actions-and-optimistic-updates.md

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,162 @@ section: "Guide"
55

66
# Async Actions and Optimistic Updates
77

8-
coming soon.
8+
When creating async actions there are generally three action types that we need
9+
10+
1. **`<ACTION>_STARTED`** represents the action happening client side but has not been verified by the server. When doing optimistic updates
11+
stores can respond to this action type as if the transaction will be successful, while maintaining enough state to rollback if it eventually fails.
12+
13+
2. **`<ACTION>_SUCCESS`** happens after the server has verified that the optimistic update is valid, at this point stores can discard rollback information without worry.
14+
15+
3. **`<ACTION>_FAILED`** the server has rejected the update and stores need to rollback.
16+
17+
### Implementing an optimistic `cartCheckout()` action
18+
19+
The first step is to track checkout rollback information in the **CartStore**
20+
21+
#### `stores/CartStore.js`
22+
23+
```javascript
24+
import { Store, toImmutable } from 'nuclear-js'
25+
import {
26+
CHECKOUT_START,
27+
CHECKOUT_SUCCESS,
28+
CHECKOUT_FAILED,
29+
ADD_TO_CART,
30+
} from '../action-types'
31+
32+
const initialState = toImmutable({
33+
itemQty: {},
34+
pendingCheckout: {},
35+
})
36+
37+
/**
38+
* CartStore holds the mapping of productId => quantity
39+
* and also maintains rollback information for the checkout process
40+
*/
41+
export default Store({
42+
getInitialState() {
43+
return initialState
44+
},
45+
46+
initialize() {
47+
this.on(CHECKOUT_START, beginCheckout)
48+
this.on(CHECKOUT_SUCCESS, finishCheckout)
49+
this.on(CHECKOUT_FAILED, rollback)
50+
this.on(ADD_TO_CART, addToCart)
51+
}
52+
})
53+
54+
function addToCart(state, { product }) {
55+
return (state.hasIn(['itemQty', product.id]))
56+
? state.updateIn(['itemQty', product.id], quantity => quantity + 1)
57+
: state.setIn(['itemQty', product.id], 1)
58+
}
59+
60+
function beginCheckout(state) {
61+
// snapshot the current itemQty map for a potential rollback
62+
const currentItems = state.get('itemQty')
63+
64+
return state
65+
.set('itemQty', toImmutable({}))
66+
.set('pendingCheckout', currentItems)
67+
}
68+
69+
function finishCheckout(state) {
70+
// on success revert CartStore to its initial state
71+
// discarding now unneeded rollback state
72+
return initialState
73+
}
74+
75+
function rollback(state) {
76+
// in the case of rollback restore the cart contents
77+
// and discard rollback information
78+
return state
79+
.set('itemQty', state.get('pendingCheckout'))
80+
.set('pendingCheckout', toImmutable({}))
81+
}
82+
```
83+
84+
### Now lets create the `cartCheckout` action
85+
86+
#### `actions.js`
87+
88+
```javascript
89+
import shop from '../../common/api/shop'
90+
import reactor from './reactor'
91+
import getters from './getters'
92+
import {
93+
RECEIVE_PRODUCTS,
94+
ADD_TO_CART,
95+
CHECKOUT_START,
96+
CHECKOUT_SUCCESS,
97+
CHECKOUT_FAILED,
98+
} from './action-types'
99+
100+
export default {
101+
fetchProducts() {
102+
shop.getProducts(products => {
103+
reactor.dispatch(RECEIVE_PRODUCTS, { products })
104+
});
105+
},
106+
107+
addToCart(product) {
108+
reactor.dispatch(ADD_TO_CART, { product })
109+
},
110+
111+
cartCheckout() {
112+
let productsInCart = reactor.evaluateToJS(getters.cartProducts)
113+
114+
reactor.dispatch(CHECKOUT_START)
115+
116+
shop.buyProducts(productsInCart, () => {
117+
console.log("YOU BOUGHT: ", productsInCart)
118+
119+
reactor.dispatch(CHECKOUT_SUCCESS)
120+
});
121+
},
122+
}
123+
```
124+
125+
### Hooking it up to the CartContainer component
126+
127+
#### `components/CartContainer.jsx`
128+
129+
```javascript
130+
import React from 'react'
131+
132+
import Cart from '../../common/components/Cart'
133+
import reactor from '../reactor'
134+
import getters from '../getters'
135+
import actions from '../actions'
136+
137+
export default React.createClass({
138+
mixins: [reactor.ReactMixin],
139+
140+
getDataBindings() {
141+
return {
142+
products: getters.cartProducts,
143+
total: getters.cartTotal,
144+
}
145+
},
146+
147+
onCheckoutClicked: function () {
148+
actions.cartCheckout()
149+
},
150+
151+
render: function () {
152+
return (
153+
<Cart products={this.state.products.toJS()} total={this.state.total} onCheckoutClicked={this.onCheckoutClicked} />
154+
)
155+
},
156+
})
157+
```
158+
159+
## Further Reading
160+
161+
This ends our getting started example, for further reading checkout the following:
162+
163+
- [API Documentation](./07-api.md)
164+
- [Shopping Cart Example Code](https://github.com/optimizely/nuclear-js/tree/master/examples/shopping-cart)
165+
- [Flux Chat Example Code](https://github.com/optimizely/nuclear-js/tree/master/examples/flux-chat)
166+

0 commit comments

Comments
 (0)