-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathislands.js
66 lines (56 loc) · 1.75 KB
/
islands.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
/*
Simple helper to let you start multiple apps on a page
with synchronized state. Useful in mostly statically/server-side
rendered pages with small islands of interactivity.
exports a function which will instantiate and return
an app-prop-decorator. If you use the same app-prop-decorator
to "wrap" the props passed to a number of apps, the state of
all those apps will be synchronized.
For initial state needed by individual synced apps, always
use actions that merge existing state with what the app
needs. If it sets the state directly/explicitly it will
undo any initial state set by other apps.
Usage:
import makeSynchromizer from './lib/synced-islands.js'
const synced = makeSynchronizer({initialProp: 'foo'})
...
//app A
app(synced({
node: elementA
init: state => ({...state, propA: 'bar'}),
view: ... // can make use of initialProp, propA, or propB
// could also specify subscriptions & dispatch
}))
// the shared state is now {initialProp: 'foo', propA: 'bar'}
...
//app B
app(synced({
init: state => ({...state, propB: 'baz'})
...
}))
// the shared state is now {initialProp: 'foo', propA: 'bar', propB: 'baz'}
*/
export default (state = {}) => {
const stateRef = { state }
const synced = []
const syncmw = dispatch => {
synced.push(dispatch)
return (action, payload) => {
const news = Array.isArray(action) ? action[0] : action
if (
typeof news !== "function" &&
stateRef.state !== news &&
news != null
) {
stateRef.state = news
synced.forEach(d => d(news))
}
dispatch(action, payload)
}
}
return props => ({
...props,
dispatch: d => syncmw(props.dispatch ? props.dispatch(d) : d),
init: [stateRef.state, !!props.init && (d => d(props.init))],
})
}