-
Notifications
You must be signed in to change notification settings - Fork 323
/
Render.js
124 lines (102 loc) · 2.91 KB
/
Render.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
import React from 'react'
export function withData(fetch, MaybeComponent) {
function bind(Component) {
return React.createClass({
contextTypes: {
buffer: React.PropTypes.object.isRequired
},
childContextTypes: {
buffer: React.PropTypes.object.isRequired
},
getChildContext() {
return { buffer: this.context.buffer }
},
componentWillMount() {
if (!this.context.buffer.locked) {
this.context.buffer.push(
fetch(this.props)
)
}
},
render() {
return this.context.buffer.locked
? React.createElement(Component, this.props)
: null
}
})
}
// works as a decorator or as a function
return MaybeComponent ? bind(MaybeComponent) : Component => bind(Component)
}
function usingDispatchBuffer(buffer, Component) {
return React.createClass({
childContextTypes: {
buffer: React.PropTypes.object.isRequired
},
getChildContext() {
return { buffer }
},
render() {
return React.createElement(Component, this.props)
}
})
}
class DispatchBuffer {
constructor(renderStrategy) {
this.promisesBuffer = []
this.locked = false
this.renderStrategy = renderStrategy
}
push(v) {
this.promisesBuffer.push(v)
}
fill(Element) {
return this.renderStrategy(Element)
}
clear() {
this.promisesBuffer = []
}
flush(Element) {
return Promise.all(this.promisesBuffer).then((data) => {
// fire off all the actions synchronously
data.forEach((f) => {
if (Array.isArray(f)) {
f.forEach(x => x())
} else {
f()
}
})
this.locked = true
return this.renderStrategy(Element)
}).catch(() => {
// if there's an error still render the markup with what we've got.
return this.renderStrategy(Element)
})
}
}
function renderWithStrategy(strategy) {
return (Component, props) => {
// create a buffer and use context to pass it through to the components
const buffer = new DispatchBuffer((Node) => {
return React[strategy](Node)
})
const Container = usingDispatchBuffer(buffer, Component)
// cache the element
const Element = React.createElement(Container, props)
// render so we kick things off and get the props
buffer.fill(Element)
// flush out the results in the buffer synchronously setting the store
// state and returning the markup
return buffer.flush(Element)
}
}
export function toDOM(Component, props, documentNode) {
const buffer = new DispatchBuffer()
buffer.locked = true
const Node = usingDispatchBuffer(buffer, Component)
const Element = React.createElement(Node, props)
buffer.clear()
return React.render(Element, documentNode)
}
export const toStaticMarkup = renderWithStrategy('renderToStaticMarkup')
export const toString = renderWithStrategy('renderToString')