-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
140 lines (125 loc) · 3.91 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import { Provider } from 'react-redux'
import fetch from 'isomorphic-fetch'
import { rereql, rereqlMiddleware, rereqlReducer, mutate, mutates } from '../../../lib'
const apiEndpoint = 'http://localhost:3000/graphql'
// we need to give the rereql middleware a fetcher, so that rereql knows how to
// execute a query. rereql will call the fetcher with the following parameters:
//
// 1) the GraphQL query
// 2) parameter values (which will be interpolated by the GraphQL service)
// 3) the current (redux) state
//
// The fetcher is expected to return a promise that will eventually resolve to
// the GraphQL response.
const fetcher = (query, params, state) => {
return fetch(apiEndpoint, {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, variables: params })
}).then(response => {
if (response.status >= 300) {
return response.json().then(json => {
const err = merge(new Error(response.statusText || 'bad response'), {
graphqlErrors: json
})
throw err
})
}
return response.json()
})
}
// for mutations, we define our own action types
const addOrderActions = [
'ADD_ORDER', 'ADD_ORDER_SUCCESS', 'ADD_ORDER_FAILURE'
]
const [ ADD_ORDER, ADD_ORDER_SUCCESS, ADD_ORDER_FAILURE ] = addOrderActions
// we create the reducer, where 'rereql' *must* be set to the rereqlReducer.
// For mutations, `mutates` maps the current state of a mutation (isMutating,
// lastError, result) into the state. See below for how to initiate a mutation.
const reducer = combineReducers({
rereql: rereqlReducer,
addOrder: mutates({
actionTypes: [ ADD_ORDER, ADD_ORDER_SUCCESS, ADD_ORDER_FAILURE ]
})
})
// middleware to alert us on new order (don't do this in production...)
const alertOnOrderAdded = store => next => action => {
if(action.type === ADD_ORDER_SUCCESS) alert('Order added. You must refresh (for now) to see it.')
return next(action)
}
// when creating the store, we must apply rereqlMiddleware
const store = createStore(
reducer,
compose(
applyMiddleware(rereqlMiddleware(fetcher), alertOnOrderAdded /*, moreMiddlewareIfNeeded */),
// activates Chrome dev tools, see https://github.com/zalmoxisus/redux-devtools-extension
window.devToolsExtension ? window.devToolsExtension() : f => f
)
)
const ordersQuery = `
query($shopId:String) {
orders(shopId:$shopId) {
id,
orderedBy,
items {
id,
quantity,
inventoryId
}
}
}
`
const addOrderQuery = `
mutation($shopId:String) {
addOrder(shopId:$shopId, tipInCents:20, items: [
{ inventoryId:"burger", quantity:2 }
]) {
createdOrder {
id
}
}
}
`
// component to query and display orders. `rereql` is a higher order function
// (similar to `connect` of react-redux) which received query and parameters,
// and can then be applied to a component (anonymous, in this example).
const OrdersList = rereql(ordersQuery, { shopId: '123' })(({ data }) => {
if (data) {
return (
<ul>
{ data.orders.map(o => (
<li key={ o.id }>Order { o.id } ordered by { o.orderedBy }</li>
))}
</ul>
)
} else {
return (<p>No orders</p>)
}
})
// component to mutate (add an order)
const AddOrderButton = mutate({
actionTypes: addOrderActions,
mapStateToQuery: (state) => addOrderQuery,
mapStateToParams: (state) => ({ shopId: '123' })
})(({ onAction }) => (
<button onClick={ onAction }>Add order</button>
))
// a plain component to combine OrdersList and AddOrderButton
const Orders = () => (
<div>
<OrdersList />
<AddOrderButton />
</div>
)
// the app needs a react-redux Provider, but nothing special otherwise
const App = () => (
<Provider store={ store }>
<Orders />
</Provider>
)
ReactDOM.render(<App />, document.getElementById('app'))