1
1
import { encodeEntities , styleObjToCss , UNSAFE_NAME , XLINK } from './util' ;
2
- import { options , Fragment } from 'preact' ;
2
+ import { options , h , Fragment } from 'preact' ;
3
3
import {
4
+ CHILDREN ,
4
5
COMMIT ,
5
6
COMPONENT ,
6
7
DIFF ,
7
8
DIFFED ,
8
9
DIRTY ,
9
10
NEXT_STATE ,
11
+ PARENT ,
10
12
RENDER ,
11
13
SKIP_EFFECTS ,
12
14
VNODE
@@ -41,8 +43,11 @@ export default function renderToString(vnode, context) {
41
43
afterDiff = options [ DIFFED ] ;
42
44
renderHook = options [ RENDER ] ;
43
45
46
+ const parent = h ( Fragment , null ) ;
47
+ parent [ CHILDREN ] = [ vnode ] ;
48
+
44
49
try {
45
- return _renderToString ( vnode , context || { } , false , undefined ) ;
50
+ return _renderToString ( vnode , context || { } , false , undefined , parent ) ;
46
51
} finally {
47
52
// options._commit, we don't schedule any effects in this library right now,
48
53
// so we can pass an empty queue to this hook.
@@ -107,9 +112,10 @@ function renderClassComponent(vnode, context) {
107
112
* @param {any } context
108
113
* @param {boolean } isSvgMode
109
114
* @param {any } selectValue
115
+ * @param {VNode } parent
110
116
* @returns {string }
111
117
*/
112
- function _renderToString ( vnode , context , isSvgMode , selectValue ) {
118
+ function _renderToString ( vnode , context , isSvgMode , selectValue , parent ) {
113
119
// Ignore non-rendered VNodes/values
114
120
if ( vnode == null || vnode === true || vnode === false || vnode === '' ) {
115
121
return '' ;
@@ -123,75 +129,85 @@ function _renderToString(vnode, context, isSvgMode, selectValue) {
123
129
// Recurse into children / Arrays
124
130
if ( isArray ( vnode ) ) {
125
131
let rendered = '' ;
132
+ parent [ CHILDREN ] = vnode ;
126
133
for ( let i = 0 ; i < vnode . length ; i ++ ) {
127
134
rendered =
128
- rendered + _renderToString ( vnode [ i ] , context , isSvgMode , selectValue ) ;
135
+ rendered +
136
+ _renderToString ( vnode [ i ] , context , isSvgMode , selectValue , parent ) ;
129
137
}
130
138
return rendered ;
131
139
}
132
140
141
+ vnode [ PARENT ] = parent ;
133
142
if ( beforeDiff ) beforeDiff ( vnode ) ;
134
143
135
144
let type = vnode . type ,
136
- props = vnode . props ;
145
+ props = vnode . props ,
146
+ cctx = context ,
147
+ contextType ,
148
+ rendered ,
149
+ component ;
137
150
138
151
// Invoke rendering on Components
139
- const isComponent = typeof type === 'function' ;
152
+ let isComponent = typeof type === 'function' ;
140
153
if ( isComponent ) {
141
154
if ( type === Fragment ) {
142
- return _renderToString ( props . children , context , isSvgMode , selectValue ) ;
143
- }
144
-
145
- let cctx = context ;
146
- let cxType = type . contextType ;
147
- if ( cxType != null ) {
148
- let provider = context [ cxType . __c ] ;
149
- cctx = provider ? provider . props . value : cxType . __ ;
150
- }
151
-
152
- let rendered ;
153
- let component ;
154
- if ( type . prototype && typeof type . prototype . render === 'function' ) {
155
- rendered = /**#__NOINLINE__**/ renderClassComponent ( vnode , cctx ) ;
156
- component = vnode [ COMPONENT ] ;
155
+ rendered = props . children ;
157
156
} else {
158
- component = {
159
- __v : vnode ,
160
- props,
161
- context : cctx ,
162
- // silently drop state updates
163
- setState : markAsDirty ,
164
- forceUpdate : markAsDirty ,
165
- __d : true ,
166
- // hooks
167
- __h : [ ]
168
- } ;
169
- vnode [ COMPONENT ] = component ;
170
-
171
- // If a hook invokes setState() to invalidate the component during rendering,
172
- // re-render it up to 25 times to allow "settling" of memoized states.
173
- // Note:
174
- // This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
175
- // https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
176
- // let renderHook = options[RENDER];
177
- let count = 0 ;
178
- while ( component [ DIRTY ] && count ++ < 25 ) {
179
- component [ DIRTY ] = false ;
180
-
181
- if ( renderHook ) renderHook ( vnode ) ;
182
-
183
- rendered = type . call ( component , props , cctx ) ;
157
+ contextType = type . contextType ;
158
+ if ( contextType != null ) {
159
+ let provider = context [ contextType . __c ] ;
160
+ cctx = provider ? provider . props . value : contextType . __ ;
184
161
}
185
- component [ DIRTY ] = true ;
186
- }
187
162
188
- if ( component . getChildContext != null ) {
189
- context = assign ( { } , context , component . getChildContext ( ) ) ;
163
+ if ( type . prototype && typeof type . prototype . render === 'function' ) {
164
+ rendered = /**#__NOINLINE__**/ renderClassComponent ( vnode , cctx ) ;
165
+ component = vnode [ COMPONENT ] ;
166
+ } else {
167
+ component = {
168
+ __v : vnode ,
169
+ props,
170
+ context : cctx ,
171
+ // silently drop state updates
172
+ setState : markAsDirty ,
173
+ forceUpdate : markAsDirty ,
174
+ __d : true ,
175
+ // hooks
176
+ __h : [ ]
177
+ } ;
178
+ vnode [ COMPONENT ] = component ;
179
+
180
+ // If a hook invokes setState() to invalidate the component during rendering,
181
+ // re-render it up to 25 times to allow "settling" of memoized states.
182
+ // Note:
183
+ // This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
184
+ // https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
185
+ let count = 0 ;
186
+ while ( component [ DIRTY ] && count ++ < 25 ) {
187
+ component [ DIRTY ] = false ;
188
+
189
+ if ( renderHook ) renderHook ( vnode ) ;
190
+
191
+ rendered = type . call ( component , props , cctx ) ;
192
+ }
193
+ component [ DIRTY ] = true ;
194
+ }
195
+
196
+ if ( component . getChildContext != null ) {
197
+ context = assign ( { } , context , component . getChildContext ( ) ) ;
198
+ }
190
199
}
191
200
192
201
// Recurse into children before invoking the after-diff hook
193
- const str = _renderToString ( rendered , context , isSvgMode , selectValue ) ;
202
+ const str = _renderToString (
203
+ rendered ,
204
+ context ,
205
+ isSvgMode ,
206
+ selectValue ,
207
+ vnode
208
+ ) ;
194
209
if ( afterDiff ) afterDiff ( vnode ) ;
210
+ vnode [ PARENT ] = undefined ;
195
211
return str ;
196
212
}
197
213
@@ -302,10 +318,11 @@ function _renderToString(vnode, context, isSvgMode, selectValue) {
302
318
// recurse into this element VNode's children
303
319
let childSvgMode =
304
320
type === 'svg' || ( type !== 'foreignObject' && isSvgMode ) ;
305
- html = _renderToString ( children , context , childSvgMode , selectValue ) ;
321
+ html = _renderToString ( children , context , childSvgMode , selectValue , vnode ) ;
306
322
}
307
323
308
324
if ( afterDiff ) afterDiff ( vnode ) ;
325
+ vnode [ PARENT ] = undefined ;
309
326
310
327
// Emit self-closing tag for empty void elements:
311
328
if ( ! html ) {
0 commit comments