@samitouri / QOS-React-2 / commits / 9c7a312d7c

Hydration of previously rendered server markup (#9580)

* Don't double validate the DOM container The warnings need to check a valid container but that should happen in unstable_renderSubtreeIntoContainer too so might as well move it in. * Hydrating DOM Hydrates a server-rendered DOM tree by traversing it and connecting up the nodes if they match. Attributes are not diffed. They're assumed to be accurate on matching nodes. * Remove meta data filtering from test Because the current server renderer includes the meta data, it remains in a revived tree. * Annotate because Flow * Don't track insertion effects if we're going to hydrate During initial mount, we should not track Placement * Fix up test cases to ignore errors that we no longer throw TODO make these warnings instead. * Correctly track hydration state inside a newly inserted tree When we don't match the first hydration node, we'll do an insertion. Currently we keep the next hydratable sibling so that we know where to pick up once we're done with the insertion. Unfortunately this makes the nodes inside the insertion think that there's a node to hydrate. I used to check for the direct parent but that doesn't work on nested host components. We need to instead keep track of that we're in an hydration context but we're not currently hydrating. Once we pop passed the inserted node can we resume hydrating. * Hacky fix to isMounted isMounted checks whether a component is inside a Placement. During hydration we ideally don't do any Placements if hydration matches the tree. To work around this I use the Placement flag on the root, which isn't used for anything else. But only temporarily while we're hydrating. Then reset it before committing. * Record tests * Comments

Sebastian Markbåge committed May 25, 2017 at 15:19 UTC 9c7a312d7c71761c520771c90338ecb8cde15e41
13 files changed +707 -283
scripts/fiber/tests-failing.txt
-133
@@ -1,132 +1,8 @@
1 src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
2 -* renders a blank div with client render on top of good server markup
3 -* renders a div with inline styles with client render on top of good server markup
4 -* renders a self-closing tag with client render on top of good server markup
5 -* renders a self-closing tag as a child with client render on top of good server markup
6 -* renders simple numbers with client render on top of good server markup
7 -* renders simple strings with client render on top of good server markup
8 -* renders string prop with true value with client render on top of good server markup
9 -* renders string prop with false value with client render on top of good server markup
10 -* renders boolean prop with true value with client render on top of good server markup
11 -* renders boolean prop with false value with client render on top of good server markup
12 -* renders boolean prop with self value with client render on top of good server markup
13 -* renders boolean prop with "" value with client render on top of good server markup
14 -* renders boolean prop with string value with client render on top of good server markup
15 -* renders boolean prop with array value with client render on top of good server markup
16 -* renders boolean prop with object value with client render on top of good server markup
17 -* renders boolean prop with non-zero number value with client render on top of good server markup
18 -* renders boolean prop with zero value with client render on top of good server markup
19 -* renders download prop with true value with client render on top of good server markup
20 -* renders download prop with false value with client render on top of good server markup
21 -* renders download prop with string value with client render on top of good server markup
22 -* renders download prop with string "true" value with client render on top of good server markup
23 -* renders className prop with string value with client render on top of good server markup
24 -* renders className prop with empty string value with client render on top of good server markup
25 -* renders className prop with true value with client render on top of good server markup
26 -* renders className prop with false value with client render on top of good server markup
27 -* renders htmlFor with string value with client render on top of good server markup
28 -* renders htmlFor with an empty string with client render on top of good server markup
29 -* renders className prop with true value with client render on top of good server markup
30 -* renders className prop with false value with client render on top of good server markup
31 -* renders no ref attribute with client render on top of good server markup
32 -* renders no children attribute with client render on top of good server markup
33 -* renders no key attribute with client render on top of good server markup
34 -* renders no dangerouslySetInnerHTML attribute with client render on top of good server markup
35 -* renders no unknown attributes with client render on top of good server markup
36 -* renders unknown data- attributes with client render on top of good server markup
37 -* renders no unknown attributes for non-standard elements with client render on top of good server markup
38 -* renders unknown attributes for custom elements with client render on top of good server markup
39 -* renders unknown attributes for custom elements using is with client render on top of good server markup
40 -* renders no HTML events with client render on top of good server markup
41 -* renders a div with text with client render on top of good server markup
42 -* renders a div with text with flanking whitespace with client render on top of good server markup
43 -* renders a div with an empty text child with client render on top of good server markup
44 -* renders a div with multiple empty text children with client render on top of good server markup
45 -* renders a div with multiple whitespace children with client render on top of good server markup
46 -* renders a div with text sibling to a node with client render on top of good server markup
47 -* renders a non-standard element with text with client render on top of good server markup
48 -* renders a custom element with text with client render on top of good server markup
49 -* renders a leading blank child with a text sibling with client render on top of good server markup
50 -* renders a trailing blank child with a text sibling with client render on top of good server markup
51 -* renders an element with two text children with client render on top of good server markup
52 -* renders a number as single child with client render on top of good server markup
53 -* renders zero as single child with client render on top of good server markup
54 -* renders an element with number and text children with client render on top of good server markup
55 -* renders null single child as blank with client render on top of good server markup
56 -* renders false single child as blank with client render on top of good server markup
57 -* renders undefined single child as blank with client render on top of good server markup
58 -* renders a null component children as empty with client render on top of good server markup
59 -* renders null children as blank with client render on top of good server markup
60 -* renders false children as blank with client render on top of good server markup
61 -* renders null and false children together as blank with client render on top of good server markup
62 -* renders only null and false children as blank with client render on top of good server markup
63 -* renders an svg element with client render on top of good server markup
64 -* renders svg element with an xlink with client render on top of good server markup
65 -* renders a math element with client render on top of good server markup
66 -* renders an img with client render on top of good server markup
67 -* renders a button with client render on top of good server markup
68 -* renders a div with dangerouslySetInnerHTML with client render on top of good server markup
69 -* renders a newline-eating tag with content not starting with \n with client render on top of good server markup
70 -* renders a newline-eating tag with content starting with \n with client render on top of good server markup
71 -* renders a normal tag with content starting with \n with client render on top of good server markup
72 -* renders stateless components with client render on top of good server markup
73 -* renders ES6 class components with client render on top of good server markup
74 -* renders factory components with client render on top of good server markup
75 -* renders single child hierarchies of components with client render on top of good server markup
76 -* renders multi-child hierarchies of components with client render on top of good server markup
77 -* renders a div with a child with client render on top of good server markup
78 -* renders a div with multiple children with client render on top of good server markup
79 -* renders a div with multiple children separated by whitespace with client render on top of good server markup
80 -* renders a div with a single child surrounded by whitespace with client render on top of good server markup
81 -* renders >,<, and & as single child with client render on top of good server markup
82 -* renders >,<, and & as multiple children with client render on top of good server markup
83 -* renders an input with a value and an onChange with client render on top of good server markup
84 -* renders an input with a value and readOnly with client render on top of good server markup
85 -* renders an input with a value and no onChange/readOnly with client render on top of good server markup
86 -* renders an input with a defaultValue with client render on top of good server markup
87 -* renders an input value overriding defaultValue with client render on top of good server markup
88 -* renders an input value overriding defaultValue no matter the prop order with client render on top of good server markup
89 -* renders a checkbox that is checked with an onChange with client render on top of good server markup
90 -* renders a checkbox that is checked with readOnly with client render on top of good server markup
91 -* renders a checkbox that is checked and no onChange/readOnly with client render on top of good server markup
92 -* renders a checkbox with defaultChecked with client render on top of good server markup
93 -* renders a checkbox checked overriding defaultChecked with client render on top of good server markup
94 -* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of good server markup
95 -* renders a textarea with a value and an onChange with client render on top of good server markup
96 -* renders a textarea with a value and readOnly with client render on top of good server markup
97 -* renders a textarea with a value and no onChange/readOnly with client render on top of good server markup
98 -* renders a textarea with a defaultValue with client render on top of good server markup
99 -* renders a textarea value overriding defaultValue with client render on top of good server markup
100 -* renders a textarea value overriding defaultValue no matter the prop order with client render on top of good server markup
101 -* renders a select with a value and an onChange with client render on top of good server markup
102 -* renders a select with a value and readOnly with client render on top of good server markup
103 -* renders a select with a multiple values and an onChange with client render on top of good server markup
104 -* renders a select with a multiple values and readOnly with client render on top of good server markup
105 -* renders a select with a value and no onChange/readOnly with client render on top of good server markup
106 -* renders a select with a defaultValue with client render on top of good server markup
107 -* renders a select value overriding defaultValue with client render on top of good server markup
108 -* renders a select value overriding defaultValue no matter the prop order with client render on top of good server markup
109 -* renders a controlled text input with client render on top of good server markup
110 -* renders a controlled textarea with client render on top of good server markup
111 -* renders a controlled checkbox with client render on top of good server markup
112 -* renders a controlled select with client render on top of good server markup
113 -* should not blow away user-entered text on successful reconnect to an uncontrolled input
114 -* should not blow away user-entered text on successful reconnect to a controlled input
2 * should not blow away user-entered text on successful reconnect to an uncontrolled checkbox
3 * should not blow away user-entered text on successful reconnect to a controlled checkbox
4 * should not blow away user-selected value on successful reconnect to an uncontrolled select
5 * should not blow away user-selected value on successful reconnect to an controlled select
119 -* renders class child with context with client render on top of good server markup
120 -* renders stateless child with context with client render on top of good server markup
121 -* renders class child without context with client render on top of good server markup
122 -* renders stateless child without context with client render on top of good server markup
123 -* renders class child with wrong context with client render on top of good server markup
124 -* renders stateless child with wrong context with client render on top of good server markup
125 -* renders with context passed through to a grandchild with client render on top of good server markup
126 -* renders a child context overriding a parent context with client render on top of good server markup
127 -* renders a child context merged with a parent context with client render on top of good server markup
128 -* renders with a call to componentWillMount before getChildContext with client render on top of good server markup
129 -* should send the correct element to ref functions on client
6
7 src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
8 * can reconcile text merged by Node.normalize() alongside other elements
@@ -136,12 +12,3 @@ src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
12
13 src/renderers/dom/shared/__tests__/ReactMount-test.js
14 * marks top-level mounts
139 -
140 -src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js
141 -* should be able to adopt server markup
142 -* should not be able to unmount component from document node
143 -* should not be able to switch root constructors
144 -* should be able to mount into document
145 -* should give helpful errors on state desync
146 -* should throw on full document render w/ no markup
147 -* supports findDOMNode on full-page components
scripts/fiber/tests-passing.txt
+133
@@ -972,166 +972,247 @@ src/renderers/dom/shared/__tests__/ReactDOMSVG-test.js
972 src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
973 * renders a blank div with server string render
974 * renders a blank div with clean client render
975 +* renders a blank div with client render on top of good server markup
976 * renders a div with inline styles with server string render
977 * renders a div with inline styles with clean client render
978 +* renders a div with inline styles with client render on top of good server markup
979 * renders a self-closing tag with server string render
980 * renders a self-closing tag with clean client render
981 +* renders a self-closing tag with client render on top of good server markup
982 * renders a self-closing tag as a child with server string render
983 * renders a self-closing tag as a child with clean client render
984 +* renders a self-closing tag as a child with client render on top of good server markup
985 * renders simple numbers with server string render
986 * renders simple numbers with clean client render
987 +* renders simple numbers with client render on top of good server markup
988 * renders simple strings with server string render
989 * renders simple strings with clean client render
990 +* renders simple strings with client render on top of good server markup
991 * renders string prop with true value with server string render
992 * renders string prop with true value with clean client render
993 +* renders string prop with true value with client render on top of good server markup
994 * renders string prop with false value with server string render
995 * renders string prop with false value with clean client render
996 +* renders string prop with false value with client render on top of good server markup
997 * renders boolean prop with true value with server string render
998 * renders boolean prop with true value with clean client render
999 +* renders boolean prop with true value with client render on top of good server markup
1000 * renders boolean prop with false value with server string render
1001 * renders boolean prop with false value with clean client render
1002 +* renders boolean prop with false value with client render on top of good server markup
1003 * renders boolean prop with self value with server string render
1004 * renders boolean prop with self value with clean client render
1005 +* renders boolean prop with self value with client render on top of good server markup
1006 * renders boolean prop with "" value with server string render
1007 * renders boolean prop with "" value with clean client render
1008 +* renders boolean prop with "" value with client render on top of good server markup
1009 * renders boolean prop with string value with server string render
1010 * renders boolean prop with string value with clean client render
1011 +* renders boolean prop with string value with client render on top of good server markup
1012 * renders boolean prop with array value with server string render
1013 * renders boolean prop with array value with clean client render
1014 +* renders boolean prop with array value with client render on top of good server markup
1015 * renders boolean prop with object value with server string render
1016 * renders boolean prop with object value with clean client render
1017 +* renders boolean prop with object value with client render on top of good server markup
1018 * renders boolean prop with non-zero number value with server string render
1019 * renders boolean prop with non-zero number value with clean client render
1020 +* renders boolean prop with non-zero number value with client render on top of good server markup
1021 * renders boolean prop with zero value with server string render
1022 * renders boolean prop with zero value with clean client render
1023 +* renders boolean prop with zero value with client render on top of good server markup
1024 * renders download prop with true value with server string render
1025 * renders download prop with true value with clean client render
1026 +* renders download prop with true value with client render on top of good server markup
1027 * renders download prop with false value with server string render
1028 * renders download prop with false value with clean client render
1029 +* renders download prop with false value with client render on top of good server markup
1030 * renders download prop with string value with server string render
1031 * renders download prop with string value with clean client render
1032 +* renders download prop with string value with client render on top of good server markup
1033 * renders download prop with string "true" value with server string render
1034 * renders download prop with string "true" value with clean client render
1035 +* renders download prop with string "true" value with client render on top of good server markup
1036 * renders className prop with string value with server string render
1037 * renders className prop with string value with clean client render
1038 +* renders className prop with string value with client render on top of good server markup
1039 * renders className prop with empty string value with server string render
1040 * renders className prop with empty string value with clean client render
1041 +* renders className prop with empty string value with client render on top of good server markup
1042 * renders className prop with true value with server string render
1043 * renders className prop with true value with clean client render
1044 +* renders className prop with true value with client render on top of good server markup
1045 * renders className prop with false value with server string render
1046 * renders className prop with false value with clean client render
1047 +* renders className prop with false value with client render on top of good server markup
1048 * renders htmlFor with string value with server string render
1049 * renders htmlFor with string value with clean client render
1050 +* renders htmlFor with string value with client render on top of good server markup
1051 * renders htmlFor with an empty string with server string render
1052 * renders htmlFor with an empty string with clean client render
1053 +* renders htmlFor with an empty string with client render on top of good server markup
1054 * renders className prop with true value with server string render
1055 * renders className prop with true value with clean client render
1056 +* renders className prop with true value with client render on top of good server markup
1057 * renders className prop with false value with server string render
1058 * renders className prop with false value with clean client render
1059 +* renders className prop with false value with client render on top of good server markup
1060 * renders no ref attribute with server string render
1061 * renders no ref attribute with clean client render
1062 +* renders no ref attribute with client render on top of good server markup
1063 * renders no children attribute with server string render
1064 * renders no children attribute with clean client render
1065 +* renders no children attribute with client render on top of good server markup
1066 * renders no key attribute with server string render
1067 * renders no key attribute with clean client render
1068 +* renders no key attribute with client render on top of good server markup
1069 * renders no dangerouslySetInnerHTML attribute with server string render
1070 * renders no dangerouslySetInnerHTML attribute with clean client render
1071 +* renders no dangerouslySetInnerHTML attribute with client render on top of good server markup
1072 * renders no unknown attributes with server string render
1073 * renders no unknown attributes with clean client render
1074 +* renders no unknown attributes with client render on top of good server markup
1075 * renders unknown data- attributes with server string render
1076 * renders unknown data- attributes with clean client render
1077 +* renders unknown data- attributes with client render on top of good server markup
1078 * renders no unknown attributes for non-standard elements with server string render
1079 * renders no unknown attributes for non-standard elements with clean client render
1080 +* renders no unknown attributes for non-standard elements with client render on top of good server markup
1081 * renders unknown attributes for custom elements with server string render
1082 * renders unknown attributes for custom elements with clean client render
1083 +* renders unknown attributes for custom elements with client render on top of good server markup
1084 * renders unknown attributes for custom elements using is with server string render
1085 * renders unknown attributes for custom elements using is with clean client render
1086 +* renders unknown attributes for custom elements using is with client render on top of good server markup
1087 * renders no HTML events with server string render
1088 * renders no HTML events with clean client render
1089 +* renders no HTML events with client render on top of good server markup
1090 * renders a div with text with server string render
1091 * renders a div with text with clean client render
1092 +* renders a div with text with client render on top of good server markup
1093 * renders a div with text with flanking whitespace with server string render
1094 * renders a div with text with flanking whitespace with clean client render
1095 +* renders a div with text with flanking whitespace with client render on top of good server markup
1096 * renders a div with an empty text child with server string render
1097 * renders a div with an empty text child with clean client render
1098 +* renders a div with an empty text child with client render on top of good server markup
1099 * renders a div with multiple empty text children with server string render
1100 * renders a div with multiple empty text children with clean client render
1101 +* renders a div with multiple empty text children with client render on top of good server markup
1102 * renders a div with multiple whitespace children with server string render
1103 * renders a div with multiple whitespace children with clean client render
1104 +* renders a div with multiple whitespace children with client render on top of good server markup
1105 * renders a div with text sibling to a node with server string render
1106 * renders a div with text sibling to a node with clean client render
1107 +* renders a div with text sibling to a node with client render on top of good server markup
1108 * renders a non-standard element with text with server string render
1109 * renders a non-standard element with text with clean client render
1110 +* renders a non-standard element with text with client render on top of good server markup
1111 * renders a custom element with text with server string render
1112 * renders a custom element with text with clean client render
1113 +* renders a custom element with text with client render on top of good server markup
1114 * renders a leading blank child with a text sibling with server string render
1115 * renders a leading blank child with a text sibling with clean client render
1116 +* renders a leading blank child with a text sibling with client render on top of good server markup
1117 * renders a trailing blank child with a text sibling with server string render
1118 * renders a trailing blank child with a text sibling with clean client render
1119 +* renders a trailing blank child with a text sibling with client render on top of good server markup
1120 * renders an element with two text children with server string render
1121 * renders an element with two text children with clean client render
1122 +* renders an element with two text children with client render on top of good server markup
1123 * renders a number as single child with server string render
1124 * renders a number as single child with clean client render
1125 +* renders a number as single child with client render on top of good server markup
1126 * renders zero as single child with server string render
1127 * renders zero as single child with clean client render
1128 +* renders zero as single child with client render on top of good server markup
1129 * renders an element with number and text children with server string render
1130 * renders an element with number and text children with clean client render
1131 +* renders an element with number and text children with client render on top of good server markup
1132 * renders null single child as blank with server string render
1133 * renders null single child as blank with clean client render
1134 +* renders null single child as blank with client render on top of good server markup
1135 * renders false single child as blank with server string render
1136 * renders false single child as blank with clean client render
1137 +* renders false single child as blank with client render on top of good server markup
1138 * renders undefined single child as blank with server string render
1139 * renders undefined single child as blank with clean client render
1140 +* renders undefined single child as blank with client render on top of good server markup
1141 * renders a null component children as empty with server string render
1142 * renders a null component children as empty with clean client render
1143 +* renders a null component children as empty with client render on top of good server markup
1144 * renders null children as blank with server string render
1145 * renders null children as blank with clean client render
1146 +* renders null children as blank with client render on top of good server markup
1147 * renders false children as blank with server string render
1148 * renders false children as blank with clean client render
1149 +* renders false children as blank with client render on top of good server markup
1150 * renders null and false children together as blank with server string render
1151 * renders null and false children together as blank with clean client render
1152 +* renders null and false children together as blank with client render on top of good server markup
1153 * renders only null and false children as blank with server string render
1154 * renders only null and false children as blank with clean client render
1155 +* renders only null and false children as blank with client render on top of good server markup
1156 * renders an svg element with server string render
1157 * renders an svg element with clean client render
1158 +* renders an svg element with client render on top of good server markup
1159 * renders svg element with an xlink with server string render
1160 * renders svg element with an xlink with clean client render
1161 +* renders svg element with an xlink with client render on top of good server markup
1162 * renders a math element with server string render
1163 * renders a math element with clean client render
1164 +* renders a math element with client render on top of good server markup
1165 * renders an img with server string render
1166 * renders an img with clean client render
1167 +* renders an img with client render on top of good server markup
1168 * renders a button with server string render
1169 * renders a button with clean client render
1170 +* renders a button with client render on top of good server markup
1171 * renders a div with dangerouslySetInnerHTML with server string render
1172 * renders a div with dangerouslySetInnerHTML with clean client render
1173 +* renders a div with dangerouslySetInnerHTML with client render on top of good server markup
1174 * renders a newline-eating tag with content not starting with \n with server string render
1175 * renders a newline-eating tag with content not starting with \n with clean client render
1176 +* renders a newline-eating tag with content not starting with \n with client render on top of good server markup
1177 * renders a newline-eating tag with content starting with \n with server string render
1178 * renders a newline-eating tag with content starting with \n with clean client render
1179 +* renders a newline-eating tag with content starting with \n with client render on top of good server markup
1180 * renders a normal tag with content starting with \n with server string render
1181 * renders a normal tag with content starting with \n with clean client render
1182 +* renders a normal tag with content starting with \n with client render on top of good server markup
1183 * renders stateless components with server string render
1184 * renders stateless components with clean client render
1185 +* renders stateless components with client render on top of good server markup
1186 * renders ES6 class components with server string render
1187 * renders ES6 class components with clean client render
1188 +* renders ES6 class components with client render on top of good server markup
1189 * renders factory components with server string render
1190 * renders factory components with clean client render
1191 +* renders factory components with client render on top of good server markup
1192 * renders single child hierarchies of components with server string render
1193 * renders single child hierarchies of components with clean client render
1194 +* renders single child hierarchies of components with client render on top of good server markup
1195 * renders multi-child hierarchies of components with server string render
1196 * renders multi-child hierarchies of components with clean client render
1197 +* renders multi-child hierarchies of components with client render on top of good server markup
1198 * renders a div with a child with server string render
1199 * renders a div with a child with clean client render
1200 +* renders a div with a child with client render on top of good server markup
1201 * renders a div with multiple children with server string render
1202 * renders a div with multiple children with clean client render
1203 +* renders a div with multiple children with client render on top of good server markup
1204 * renders a div with multiple children separated by whitespace with server string render
1205 * renders a div with multiple children separated by whitespace with clean client render
1206 +* renders a div with multiple children separated by whitespace with client render on top of good server markup
1207 * renders a div with a single child surrounded by whitespace with server string render
1208 * renders a div with a single child surrounded by whitespace with clean client render
1209 +* renders a div with a single child surrounded by whitespace with client render on top of good server markup
1210 * renders >,<, and & as single child with server string render
1211 * renders >,<, and & as single child with clean client render
1212 +* renders >,<, and & as single child with client render on top of good server markup
1213 * renders >,<, and & as multiple children with server string render
1214 * renders >,<, and & as multiple children with clean client render
1215 +* renders >,<, and & as multiple children with client render on top of good server markup
1216 * throws when rendering a string component with server string render
1217 * throws when rendering an undefined component with server string render
1218 * throws when rendering a number component with server string render
@@ -1152,80 +1233,122 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
1233 * throws when rendering string with client render on top of bad server markup
1234 * renders an input with a value and an onChange with server string render
1235 * renders an input with a value and an onChange with clean client render
1236 +* renders an input with a value and an onChange with client render on top of good server markup
1237 * renders an input with a value and readOnly with server string render
1238 * renders an input with a value and readOnly with clean client render
1239 +* renders an input with a value and readOnly with client render on top of good server markup
1240 * renders an input with a value and no onChange/readOnly with server string render
1241 * renders an input with a value and no onChange/readOnly with clean client render
1242 +* renders an input with a value and no onChange/readOnly with client render on top of good server markup
1243 * renders an input with a defaultValue with server string render
1244 * renders an input with a defaultValue with clean client render
1245 +* renders an input with a defaultValue with client render on top of good server markup
1246 * renders an input value overriding defaultValue with server string render
1247 * renders an input value overriding defaultValue with clean client render
1248 +* renders an input value overriding defaultValue with client render on top of good server markup
1249 * renders an input value overriding defaultValue no matter the prop order with server string render
1250 * renders an input value overriding defaultValue no matter the prop order with clean client render
1251 +* renders an input value overriding defaultValue no matter the prop order with client render on top of good server markup
1252 * renders a checkbox that is checked with an onChange with server string render
1253 * renders a checkbox that is checked with an onChange with clean client render
1254 +* renders a checkbox that is checked with an onChange with client render on top of good server markup
1255 * renders a checkbox that is checked with readOnly with server string render
1256 * renders a checkbox that is checked with readOnly with clean client render
1257 +* renders a checkbox that is checked with readOnly with client render on top of good server markup
1258 * renders a checkbox that is checked and no onChange/readOnly with server string render
1259 * renders a checkbox that is checked and no onChange/readOnly with clean client render
1260 +* renders a checkbox that is checked and no onChange/readOnly with client render on top of good server markup
1261 * renders a checkbox with defaultChecked with server string render
1262 * renders a checkbox with defaultChecked with clean client render
1263 +* renders a checkbox with defaultChecked with client render on top of good server markup
1264 * renders a checkbox checked overriding defaultChecked with server string render
1265 * renders a checkbox checked overriding defaultChecked with clean client render
1266 +* renders a checkbox checked overriding defaultChecked with client render on top of good server markup
1267 * renders a checkbox checked overriding defaultChecked no matter the prop order with server string render
1268 * renders a checkbox checked overriding defaultChecked no matter the prop order with clean client render
1269 +* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of good server markup
1270 * renders a textarea with a value and an onChange with server string render
1271 * renders a textarea with a value and an onChange with clean client render
1272 +* renders a textarea with a value and an onChange with client render on top of good server markup
1273 * renders a textarea with a value and readOnly with server string render
1274 * renders a textarea with a value and readOnly with clean client render
1275 +* renders a textarea with a value and readOnly with client render on top of good server markup
1276 * renders a textarea with a value and no onChange/readOnly with server string render
1277 * renders a textarea with a value and no onChange/readOnly with clean client render
1278 +* renders a textarea with a value and no onChange/readOnly with client render on top of good server markup
1279 * renders a textarea with a defaultValue with server string render
1280 * renders a textarea with a defaultValue with clean client render
1281 +* renders a textarea with a defaultValue with client render on top of good server markup
1282 * renders a textarea value overriding defaultValue with server string render
1283 * renders a textarea value overriding defaultValue with clean client render
1284 +* renders a textarea value overriding defaultValue with client render on top of good server markup
1285 * renders a textarea value overriding defaultValue no matter the prop order with server string render
1286 * renders a textarea value overriding defaultValue no matter the prop order with clean client render
1287 +* renders a textarea value overriding defaultValue no matter the prop order with client render on top of good server markup
1288 * renders a select with a value and an onChange with server string render
1289 * renders a select with a value and an onChange with clean client render
1290 +* renders a select with a value and an onChange with client render on top of good server markup
1291 * renders a select with a value and readOnly with server string render
1292 * renders a select with a value and readOnly with clean client render
1293 +* renders a select with a value and readOnly with client render on top of good server markup
1294 * renders a select with a multiple values and an onChange with server string render
1295 * renders a select with a multiple values and an onChange with clean client render
1296 +* renders a select with a multiple values and an onChange with client render on top of good server markup
1297 * renders a select with a multiple values and readOnly with server string render
1298 * renders a select with a multiple values and readOnly with clean client render
1299 +* renders a select with a multiple values and readOnly with client render on top of good server markup
1300 * renders a select with a value and no onChange/readOnly with server string render
1301 * renders a select with a value and no onChange/readOnly with clean client render
1302 +* renders a select with a value and no onChange/readOnly with client render on top of good server markup
1303 * renders a select with a defaultValue with server string render
1304 * renders a select with a defaultValue with clean client render
1305 +* renders a select with a defaultValue with client render on top of good server markup
1306 * renders a select value overriding defaultValue with server string render
1307 * renders a select value overriding defaultValue with clean client render
1308 +* renders a select value overriding defaultValue with client render on top of good server markup
1309 * renders a select value overriding defaultValue no matter the prop order with server string render
1310 * renders a select value overriding defaultValue no matter the prop order with clean client render
1311 +* renders a select value overriding defaultValue no matter the prop order with client render on top of good server markup
1312 * renders a controlled text input with clean client render
1313 +* renders a controlled text input with client render on top of good server markup
1314 * renders a controlled textarea with clean client render
1315 +* renders a controlled textarea with client render on top of good server markup
1316 * renders a controlled checkbox with clean client render
1317 +* renders a controlled checkbox with client render on top of good server markup
1318 * renders a controlled select with clean client render
1319 +* renders a controlled select with client render on top of good server markup
1320 +* should not blow away user-entered text on successful reconnect to an uncontrolled input
1321 +* should not blow away user-entered text on successful reconnect to a controlled input
1322 * renders class child with context with server string render
1323 * renders class child with context with clean client render
1324 +* renders class child with context with client render on top of good server markup
1325 * renders stateless child with context with server string render
1326 * renders stateless child with context with clean client render
1327 +* renders stateless child with context with client render on top of good server markup
1328 * renders class child without context with server string render
1329 * renders class child without context with clean client render
1330 +* renders class child without context with client render on top of good server markup
1331 * renders stateless child without context with server string render
1332 * renders stateless child without context with clean client render
1333 +* renders stateless child without context with client render on top of good server markup
1334 * renders class child with wrong context with server string render
1335 * renders class child with wrong context with clean client render
1336 +* renders class child with wrong context with client render on top of good server markup
1337 * renders stateless child with wrong context with server string render
1338 * renders stateless child with wrong context with clean client render
1339 +* renders stateless child with wrong context with client render on top of good server markup
1340 * renders with context passed through to a grandchild with server string render
1341 * renders with context passed through to a grandchild with clean client render
1342 +* renders with context passed through to a grandchild with client render on top of good server markup
1343 * renders a child context overriding a parent context with server string render
1344 * renders a child context overriding a parent context with clean client render
1345 +* renders a child context overriding a parent context with client render on top of good server markup
1346 * renders a child context merged with a parent context with server string render
1347 * renders a child context merged with a parent context with clean client render
1348 +* renders a child context merged with a parent context with client render on top of good server markup
1349 * renders with a call to componentWillMount before getChildContext with server string render
1350 * renders with a call to componentWillMount before getChildContext with clean client render
1351 +* renders with a call to componentWillMount before getChildContext with client render on top of good server markup
1352 * throws when rendering if getChildContext exists without childContextTypes with server string render
1353 * throws when rendering if getChildContext exists without childContextTypes with clean client render
1354 * throws when rendering if getChildContext exists without childContextTypes with client render on top of bad server markup
@@ -1234,6 +1357,7 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
1357 * throws when rendering if getChildContext returns a value not in childContextTypes with client render on top of bad server markup
1358 * should not run ref code on server
1359 * should run ref code on client
1360 +* should send the correct element to ref functions on client
1361 * should have string refs on client when rendered over server markup
1362 * should reconnect ES6 Class to ES6 Class
1363 * should reconnect Pure Component to ES6 Class
@@ -1274,6 +1398,15 @@ src/renderers/dom/shared/__tests__/ReactMount-test.js
1398 src/renderers/dom/shared/__tests__/ReactMountDestruction-test.js
1399 * should destroy a react root upon request
1400
1401 +src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js
1402 +* should be able to adopt server markup
1403 +* should not be able to unmount component from document node
1404 +* should not be able to switch root constructors
1405 +* should be able to mount into document
1406 +* should give helpful errors on state desync
1407 +* should throw on full document render w/ no markup
1408 +* supports findDOMNode on full-page components
1409 +
1410 src/renderers/dom/shared/__tests__/ReactServerRendering-test.js
1411 * should generate simple markup
1412 * should generate simple markup for self-closing tags
src/renderers/dom/fiber/ReactDOMFiber.js
+121 -55
@@ -36,6 +36,7 @@ var {
36 DOCUMENT_NODE,
37 DOCUMENT_FRAGMENT_NODE,
38 } = require('HTMLNodeType');
39 +var {ID_ATTRIBUTE_NAME} = require('DOMProperty');
40
41 var findDOMNode = require('findDOMNode');
42 var invariant = require('fbjs/lib/invariant');
@@ -63,9 +64,11 @@ findDOMNode._injectFiber(function(fiber: Fiber) {
64 return DOMRenderer.findHostInstance(fiber);
65 });
66
66 -type DOMContainerElement = Element & {_reactRootContainer: ?Object};
67 +type DOMContainer =
68 + | (Element & {_reactRootContainer: ?Object})
69 + | (Document & {_reactRootContainer: ?Object});
70
68 -type Container = Element;
71 +type Container = Element | Document;
72 type Props = {
73 autoFocus?: boolean,
74 children?: mixed,
@@ -98,12 +101,6 @@ function isValidContainer(node) {
101 node.nodeType === DOCUMENT_FRAGMENT_NODE));
102 }
103
101 -function validateContainer(container) {
102 - if (!isValidContainer(container)) {
103 - throw new Error('Target container is not a DOM element.');
104 - }
105 -}
106 -
104 function getReactRootElementInContainer(container: any) {
105 if (!container) {
106 return null;
@@ -116,6 +113,11 @@ function getReactRootElementInContainer(container: any) {
113 }
114 }
115
116 +function shouldReuseContent(container) {
117 + const rootElement = getReactRootElementInContainer(container);
118 + return !!(rootElement && rootElement.getAttribute(ID_ATTRIBUTE_NAME));
119 +}
120 +
121 function shouldAutoFocusHostComponent(type: string, props: Props): boolean {
122 switch (type) {
123 case 'button':
@@ -129,16 +131,19 @@ function shouldAutoFocusHostComponent(type: string, props: Props): boolean {
131
132 var DOMRenderer = ReactFiberReconciler({
133 getRootHostContext(rootContainerInstance: Container): HostContext {
132 - const ownNamespace = rootContainerInstance.namespaceURI || null;
133 - const type = rootContainerInstance.tagName;
134 - const namespace = getChildNamespace(ownNamespace, type);
134 + let type;
135 + let namespace;
136 + if (rootContainerInstance.nodeType === DOCUMENT_NODE) {
137 + type = '#document';
138 + let root = (rootContainerInstance: any).documentElement;
139 + namespace = root ? root.namespaceURI : getChildNamespace(null, '');
140 + } else {
141 + const ownNamespace = (rootContainerInstance: any).namespaceURI || null;
142 + type = (rootContainerInstance: any).tagName;
143 + namespace = getChildNamespace(ownNamespace, type);
144 + }
145 if (__DEV__) {
136 - const isMountingIntoDocument =
137 - rootContainerInstance.ownerDocument.documentElement ===
138 - rootContainerInstance;
139 - const validatedTag = isMountingIntoDocument
140 - ? '#document'
141 - : type.toLowerCase();
146 + const validatedTag = type.toLowerCase();
147 const ancestorInfo = updatedAncestorInfo(null, validatedTag, null);
148 return {namespace, ancestorInfo};
149 }
@@ -360,6 +365,65 @@ var DOMRenderer = ReactFiberReconciler({
365 parentInstance.removeChild(child);
366 },
367
368 + canHydrateInstance(
369 + instance: Instance | TextInstance,
370 + type: string,
371 + props: Props,
372 + ): boolean {
373 + return instance.nodeType === 1 && type === instance.nodeName.toLowerCase();
374 + },
375 +
376 + canHydrateTextInstance(instance: Instance | TextInstance): boolean {
377 + return instance.nodeType === 3;
378 + },
379 +
380 + getNextHydratableSibling(
381 + instance: Instance | TextInstance,
382 + ): null | Instance | TextInstance {
383 + let node = instance.nextSibling;
384 + // Skip non-hydratable nodes.
385 + /*
386 + while (node && node.nodeType !== 1 && node.nodeType !== 3) {
387 + node = node.nextSibling;
388 + }
389 + */
390 + return (node: any);
391 + },
392 +
393 + getFirstHydratableChild(
394 + parentInstance: Container | Instance,
395 + ): null | Instance | TextInstance {
396 + let next = parentInstance.firstChild;
397 + // Skip non-hydratable nodes.
398 + /*
399 + while (next && next.nodeType !== 1 && next.nodeType !== 3) {
400 + next = next.nextSibling;
401 + }
402 + */
403 + return (next: any);
404 + },
405 +
406 + hydrateInstance(
407 + instance: Instance,
408 + type: string,
409 + props: Props,
410 + rootContainerInstance: Container,
411 + internalInstanceHandle: Object,
412 + ): void {
413 + precacheFiberNode(internalInstanceHandle, instance);
414 + // TODO: Possibly defer this until the commit phase where all the events
415 + // get attached.
416 + updateFiberProps(instance, props);
417 + setInitialProperties(instance, type, props, rootContainerInstance);
418 + },
419 +
420 + hydrateTextInstance(
421 + textInstance: TextInstance,
422 + internalInstanceHandle: Object,
423 + ): void {
424 + precacheFiberNode(internalInstanceHandle, textInstance);
425 + },
426 +
427 scheduleAnimationCallback: ReactDOMFrameScheduling.rAF,
428
429 scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
@@ -386,19 +450,48 @@ function warnAboutUnstableUse() {
450 function renderSubtreeIntoContainer(
451 parentComponent: ?ReactComponent<any, any, any>,
452 children: ReactNodeList,
389 - containerNode: DOMContainerElement | Document,
453 + container: DOMContainer,
454 callback: ?Function,
455 ) {
392 - validateContainer(containerNode);
456 + invariant(
457 + isValidContainer(container),
458 + 'Target container is not a DOM element.',
459 + );
460 +
461 + if (__DEV__) {
462 + const isRootRenderedBySomeReact = !!container._reactRootContainer;
463 + const rootEl = getReactRootElementInContainer(container);
464 + const hasNonRootReactChild = !!(rootEl &&
465 + ReactDOMComponentTree.getInstanceFromNode(rootEl));
466 +
467 + warning(
468 + !hasNonRootReactChild || isRootRenderedBySomeReact,
469 + 'render(...): Replacing React-rendered children with a new root ' +
470 + 'component. If you intended to update the children of this node, ' +
471 + 'you should instead have the existing children update their state ' +
472 + 'and render the new components instead of calling ReactDOM.render.',
473 + );
474 +
475 + warning(
476 + container.nodeType !== 1 ||
477 + !container.tagName ||
478 + container.tagName.toUpperCase() !== 'BODY',
479 + 'render(): Rendering components directly into document.body is ' +
480 + 'discouraged, since its children are often manipulated by third-party ' +
481 + 'scripts and browser extensions. This may lead to subtle ' +
482 + 'reconciliation issues. Try rendering into a container element created ' +
483 + 'for your app.',
484 + );
485 + }
486
394 - let container: DOMContainerElement = containerNode.nodeType === DOCUMENT_NODE
395 - ? (containerNode: any).documentElement
396 - : (containerNode: any);
487 let root = container._reactRootContainer;
488 if (!root) {
489 // First clear any existing content.
400 - while (container.lastChild) {
401 - container.removeChild(container.lastChild);
490 + // TODO: Figure out the best heuristic here.
491 + if (!shouldReuseContent(container)) {
492 + while (container.lastChild) {
493 + container.removeChild(container.lastChild);
494 + }
495 }
496 const newRoot = DOMRenderer.createContainer(container);
497 root = container._reactRootContainer = newRoot;
@@ -415,11 +508,9 @@ function renderSubtreeIntoContainer(
508 var ReactDOM = {
509 render(
510 element: ReactElement<any>,
418 - container: DOMContainerElement,
511 + container: DOMContainer,
512 callback: ?Function,
513 ) {
421 - validateContainer(container);
422 -
514 if (ReactFeatureFlags.disableNewFiberFeatures) {
515 // Top-level check occurs here instead of inside child reconciler because
516 // because requirements vary between renderers. E.g. React Art
@@ -452,38 +543,13 @@ var ReactDOM = {
543 }
544 }
545 }
455 -
456 - if (__DEV__) {
457 - const isRootRenderedBySomeReact = !!container._reactRootContainer;
458 - const rootEl = getReactRootElementInContainer(container);
459 - const hasNonRootReactChild = !!(rootEl &&
460 - ReactDOMComponentTree.getInstanceFromNode(rootEl));
461 -
462 - warning(
463 - !hasNonRootReactChild || isRootRenderedBySomeReact,
464 - 'render(...): Replacing React-rendered children with a new root ' +
465 - 'component. If you intended to update the children of this node, ' +
466 - 'you should instead have the existing children update their state ' +
467 - 'and render the new components instead of calling ReactDOM.render.',
468 - );
469 -
470 - warning(
471 - !container.tagName || container.tagName.toUpperCase() !== 'BODY',
472 - 'render(): Rendering components directly into document.body is ' +
473 - 'discouraged, since its children are often manipulated by third-party ' +
474 - 'scripts and browser extensions. This may lead to subtle ' +
475 - 'reconciliation issues. Try rendering into a container element created ' +
476 - 'for your app.',
477 - );
478 - }
479 -
546 return renderSubtreeIntoContainer(null, element, container, callback);
547 },
548
549 unstable_renderSubtreeIntoContainer(
550 parentComponent: ReactComponent<any, any, any>,
551 element: ReactElement<any>,
486 - containerNode: DOMContainerElement | Document,
552 + containerNode: DOMContainer,
553 callback: ?Function,
554 ) {
555 invariant(
@@ -498,7 +564,7 @@ var ReactDOM = {
564 );
565 },
566
501 - unmountComponentAtNode(container: DOMContainerElement) {
567 + unmountComponentAtNode(container: DOMContainer) {
568 invariant(
569 isValidContainer(container),
570 'unmountComponentAtNode(...): Target container is not a DOM element.',
@@ -535,7 +601,7 @@ var ReactDOM = {
601
602 unstable_createPortal(
603 children: ReactNodeList,
538 - container: DOMContainerElement,
604 + container: DOMContainer,
605 key: ?string = null,
606 ) {
607 // TODO: pass ReactDOM portal implementation as third argument
src/renderers/dom/fiber/ReactDOMFiberComponent.js
+12 -8
@@ -23,7 +23,7 @@ var ReactDOMFiberOption = require('ReactDOMFiberOption');
23 var ReactDOMFiberSelect = require('ReactDOMFiberSelect');
24 var ReactDOMFiberTextarea = require('ReactDOMFiberTextarea');
25 var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
26 -var {DOCUMENT_FRAGMENT_NODE} = require('HTMLNodeType');
26 +var {DOCUMENT_NODE, DOCUMENT_FRAGMENT_NODE} = require('HTMLNodeType');
27
28 var assertValidProps = require('assertValidProps');
29 var emptyFunction = require('fbjs/lib/emptyFunction');
@@ -72,9 +72,10 @@ if (__DEV__) {
72 }
73
74 function ensureListeningTo(rootContainerElement, registrationName) {
75 - var isDocumentFragment =
75 + var isDocumentOrFragment =
76 + rootContainerElement.nodeType === DOCUMENT_NODE ||
77 rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE;
77 - var doc = isDocumentFragment
78 + var doc = isDocumentOrFragment
79 ? rootContainerElement
80 : rootContainerElement.ownerDocument;
81 listenTo(registrationName, doc);
@@ -171,7 +172,7 @@ function trapBubbledEventsLocal(node: Element, tag: string) {
172
173 function setInitialDOMProperties(
174 domElement: Element,
174 - rootContainerElement: Element,
175 + rootContainerElement: Element | Document,
176 nextProps: Object,
177 isCustomComponentTag: boolean,
178 ): void {
@@ -304,12 +305,15 @@ var ReactDOMFiberComponent = {
305 createElement(
306 type: string,
307 props: Object,
307 - rootContainerElement: Element,
308 + rootContainerElement: Element | Document,
309 parentNamespace: string,
310 ): Element {
311 // We create tags in the namespace of their parent container, except HTML
312 // tags get no namespace.
312 - var ownerDocument = rootContainerElement.ownerDocument;
313 + var ownerDocument: Document = rootContainerElement.nodeType ===
314 + DOCUMENT_NODE
315 + ? (rootContainerElement: any)
316 + : rootContainerElement.ownerDocument;
317 var domElement: Element;
318 var namespaceURI = parentNamespace;
319 if (namespaceURI === HTML_NAMESPACE) {
@@ -369,7 +373,7 @@ var ReactDOMFiberComponent = {
373 domElement: Element,
374 tag: string,
375 rawProps: Object,
372 - rootContainerElement: Element,
376 + rootContainerElement: Element | Document,
377 ): void {
378 var isCustomComponentTag = isCustomComponent(tag, rawProps);
379 if (__DEV__) {
@@ -472,7 +476,7 @@ var ReactDOMFiberComponent = {
476 tag: string,
477 lastRawProps: Object,
478 nextRawProps: Object,
475 - rootContainerElement: Element,
479 + rootContainerElement: Element | Document,
480 ): null | Array<mixed> {
481 if (__DEV__) {
482 validatePropertiesInDevelopment(tag, nextRawProps);
src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js
+61 -52
@@ -14,11 +14,10 @@
14 var React;
15 var ReactDOM;
16 var ReactDOMServer;
17 +var ReactDOMFeatureFlags;
18
19 var getTestDocument;
20
20 -var testDocument;
21 -
21 var UNMOUNT_INVARIANT_MESSAGE =
22 '<html> tried to unmount. ' +
23 'Because of cross-browser quirks it is impossible to unmount some ' +
@@ -33,14 +32,11 @@ describe('rendering React components at document', () => {
32 React = require('react');
33 ReactDOM = require('react-dom');
34 ReactDOMServer = require('react-dom/server');
35 + ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
36 getTestDocument = require('getTestDocument');
37 -
38 - testDocument = getTestDocument();
37 });
38
39 it('should be able to adopt server markup', () => {
42 - expect(testDocument).not.toBeUndefined();
43 -
40 class Root extends React.Component {
41 render() {
42 return (
@@ -57,7 +53,7 @@ describe('rendering React components at document', () => {
53 }
54
55 var markup = ReactDOMServer.renderToString(<Root hello="world" />);
60 - testDocument = getTestDocument(markup);
56 + var testDocument = getTestDocument(markup);
57 var body = testDocument.body;
58
59 ReactDOM.render(<Root hello="world" />, testDocument);
@@ -66,12 +62,10 @@ describe('rendering React components at document', () => {
62 ReactDOM.render(<Root hello="moon" />, testDocument);
63 expect(testDocument.body.innerHTML).toBe('Hello moon');
64
69 - expect(body).toBe(testDocument.body);
65 + expect(body === testDocument.body).toBe(true);
66 });
67
68 it('should not be able to unmount component from document node', () => {
73 - expect(testDocument).not.toBeUndefined();
74 -
69 class Root extends React.Component {
70 render() {
71 return (
@@ -88,20 +82,24 @@ describe('rendering React components at document', () => {
82 }
83
84 var markup = ReactDOMServer.renderToString(<Root />);
91 - testDocument = getTestDocument(markup);
85 + var testDocument = getTestDocument(markup);
86 ReactDOM.render(<Root />, testDocument);
87 expect(testDocument.body.innerHTML).toBe('Hello world');
88
95 - expect(function() {
89 + if (ReactDOMFeatureFlags.useFiber) {
90 + // In Fiber this actually works. It might not be a good idea though.
91 ReactDOM.unmountComponentAtNode(testDocument);
97 - }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
92 + expect(testDocument.firstChild).toBe(null);
93 + } else {
94 + expect(function() {
95 + ReactDOM.unmountComponentAtNode(testDocument);
96 + }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
97
99 - expect(testDocument.body.innerHTML).toBe('Hello world');
98 + expect(testDocument.body.innerHTML).toBe('Hello world');
99 + }
100 });
101
102 it('should not be able to switch root constructors', () => {
103 - expect(testDocument).not.toBeUndefined();
104 -
103 class Component extends React.Component {
104 render() {
105 return (
@@ -133,23 +131,28 @@ describe('rendering React components at document', () => {
131 }
132
133 var markup = ReactDOMServer.renderToString(<Component />);
136 - testDocument = getTestDocument(markup);
134 + var testDocument = getTestDocument(markup);
135
136 ReactDOM.render(<Component />, testDocument);
137
138 expect(testDocument.body.innerHTML).toBe('Hello world');
139
140 // Reactive update
143 - expect(function() {
141 + if (ReactDOMFeatureFlags.useFiber) {
142 + // This works but is probably a bad idea.
143 ReactDOM.render(<Component2 />, testDocument);
145 - }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
144
147 - expect(testDocument.body.innerHTML).toBe('Hello world');
145 + expect(testDocument.body.innerHTML).toBe('Goodbye world');
146 + } else {
147 + expect(function() {
148 + ReactDOM.render(<Component2 />, testDocument);
149 + }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
150 +
151 + expect(testDocument.body.innerHTML).toBe('Hello world');
152 + }
153 });
154
155 it('should be able to mount into document', () => {
151 - expect(testDocument).not.toBeUndefined();
152 -
156 class Component extends React.Component {
157 render() {
158 return (
@@ -168,7 +171,7 @@ describe('rendering React components at document', () => {
171 var markup = ReactDOMServer.renderToString(
172 <Component text="Hello world" />,
173 );
171 - testDocument = getTestDocument(markup);
174 + var testDocument = getTestDocument(markup);
175
176 ReactDOM.render(<Component text="Hello world" />, testDocument);
177
@@ -176,8 +179,6 @@ describe('rendering React components at document', () => {
179 });
180
181 it('should give helpful errors on state desync', () => {
179 - expect(testDocument).not.toBeUndefined();
180 -
182 class Component extends React.Component {
183 render() {
184 return (
@@ -196,29 +197,32 @@ describe('rendering React components at document', () => {
197 var markup = ReactDOMServer.renderToString(
198 <Component text="Goodbye world" />,
199 );
199 - testDocument = getTestDocument(markup);
200 + var testDocument = getTestDocument(markup);
201
201 - expect(function() {
202 - // Notice the text is different!
202 + if (ReactDOMFeatureFlags.useFiber) {
203 ReactDOM.render(<Component text="Hello world" />, testDocument);
204 - }).toThrowError(
205 - "You're trying to render a component to the document using " +
206 - 'server rendering but the checksum was invalid. This usually ' +
207 - 'means you rendered a different component type or props on ' +
208 - 'the client from the one on the server, or your render() methods ' +
209 - 'are impure. React cannot handle this case due to cross-browser ' +
210 - 'quirks by rendering at the document root. You should look for ' +
211 - 'environment dependent code in your components and ensure ' +
212 - 'the props are the same client and server side:\n' +
213 - ' (client) dy data-reactid="4">Hello world</body></\n' +
214 - ' (server) dy data-reactid="4">Goodbye world</body>',
215 - );
204 + expect(testDocument.body.innerHTML).toBe('Hello world');
205 + } else {
206 + expect(function() {
207 + // Notice the text is different!
208 + ReactDOM.render(<Component text="Hello world" />, testDocument);
209 + }).toThrowError(
210 + "You're trying to render a component to the document using " +
211 + 'server rendering but the checksum was invalid. This usually ' +
212 + 'means you rendered a different component type or props on ' +
213 + 'the client from the one on the server, or your render() methods ' +
214 + 'are impure. React cannot handle this case due to cross-browser ' +
215 + 'quirks by rendering at the document root. You should look for ' +
216 + 'environment dependent code in your components and ensure ' +
217 + 'the props are the same client and server side:\n' +
218 + ' (client) dy data-reactid="4">Hello world</body></\n' +
219 + ' (server) dy data-reactid="4">Goodbye world</body>',
220 + );
221 + }
222 });
223
224 it('should throw on full document render w/ no markup', () => {
219 - expect(testDocument).not.toBeUndefined();
220 -
221 - var container = testDocument;
225 + var testDocument = getTestDocument();
226
227 class Component extends React.Component {
228 render() {
@@ -235,14 +239,19 @@ describe('rendering React components at document', () => {
239 }
240 }
241
238 - expect(function() {
239 - ReactDOM.render(<Component />, container);
240 - }).toThrowError(
241 - "You're trying to render a component to the document but you didn't " +
242 - "use server rendering. We can't do this without using server " +
243 - 'rendering due to cross-browser quirks. See ' +
244 - 'ReactDOMServer.renderToString() for server rendering.',
245 - );
242 + if (ReactDOMFeatureFlags.useFiber) {
243 + ReactDOM.render(<Component text="Hello world" />, testDocument);
244 + expect(testDocument.body.innerHTML).toBe('Hello world');
245 + } else {
246 + expect(function() {
247 + ReactDOM.render(<Component />, testDocument);
248 + }).toThrowError(
249 + "You're trying to render a component to the document but you didn't " +
250 + "use server rendering. We can't do this without using server " +
251 + 'rendering due to cross-browser quirks. See ' +
252 + 'ReactDOMServer.renderToString() for server rendering.',
253 + );
254 + }
255 });
256
257 it('supports findDOMNode on full-page components', () => {
@@ -258,7 +267,7 @@ describe('rendering React components at document', () => {
267 );
268
269 var markup = ReactDOMServer.renderToString(tree);
261 - testDocument = getTestDocument(markup);
270 + var testDocument = getTestDocument(markup);
271 var component = ReactDOM.render(tree, testDocument);
272 expect(testDocument.body.innerHTML).toBe('Hello world');
273 expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML');
src/renderers/dom/shared/__tests__/ReactServerRendering-test.js
+1 -4
@@ -268,11 +268,8 @@ describe('ReactDOMServer', () => {
268
269 var expectedMarkup = lastMarkup;
270 if (ReactDOMFeatureFlags.useFiber) {
271 - var reactMetaData = /\s+data-react[a-z-]+="[^"]*"/g;
271 var reactComments = /<!-- \/?react-text(: \d+)? -->/g;
273 - expectedMarkup = expectedMarkup
274 - .replace(reactMetaData, '')
275 - .replace(reactComments, '');
272 + expectedMarkup = expectedMarkup.replace(reactComments, '');
273 }
274 expect(element.innerHTML).toBe(expectedMarkup);
275
src/renderers/shared/fiber/ReactFiber.js
+6
@@ -436,6 +436,12 @@ function createFiberFromElementType(
436
437 exports.createFiberFromElementType = createFiberFromElementType;
438
439 +exports.createFiberFromHostInstanceForDeletion = function(): Fiber {
440 + const fiber = createFiber(HostComponent, null, NoContext);
441 + fiber.type = 'DELETED';
442 + return fiber;
443 +};
444 +
445 exports.createFiberFromCoroutine = function(
446 coroutine: ReactCoroutine,
447 internalContextTag: TypeOfInternalContext,
src/renderers/shared/fiber/ReactFiberBeginWork.js
+45
@@ -15,6 +15,7 @@
15 import type {ReactCoroutine} from 'ReactTypes';
16 import type {Fiber} from 'ReactFiber';
17 import type {HostContext} from 'ReactFiberHostContext';
18 +import type {HydrationContext} from 'ReactFiberHydrationContext';
19 import type {FiberRoot} from 'ReactFiberRoot';
20 import type {HostConfig} from 'ReactFiberReconciler';
21 import type {PriorityLevel} from 'ReactPriorityLevel';
@@ -65,6 +66,7 @@ if (__DEV__) {
66 module.exports = function<T, P, I, TI, PI, C, CX, PL>(
67 config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
68 hostContext: HostContext<C, CX>,
69 + hydrationContext: HydrationContext<I, TI>,
70 scheduleUpdate: (fiber: Fiber, priorityLevel: PriorityLevel) => void,
71 getPriorityContext: (fiber: Fiber, forceAsync: boolean) => PriorityLevel,
72 ) {
@@ -76,6 +78,12 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
78
79 const {pushHostContext, pushHostContainer} = hostContext;
80
81 + const {
82 + enterHydrationState,
83 + resetHydrationState,
84 + tryToClaimNextHydratableInstance,
85 + } = hydrationContext;
86 +
87 const {
88 adoptClassInstance,
89 constructClassInstance,
@@ -349,13 +357,43 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
357 if (prevState === state) {
358 // If the state is the same as before, that's a bailout because we had
359 // no work matching this priority.
360 + resetHydrationState();
361 return bailoutOnAlreadyFinishedWork(current, workInProgress);
362 }
363 const element = state.element;
364 + if (current === null || current.child === null) {
365 + // If we don't have any current children this might be the first pass.
366 + // We always try to hydrate. If this isn't a hydration pass there won't
367 + // be any children to hydrate which is effectively the same thing as
368 + // not hydrating.
369 + if (enterHydrationState(workInProgress)) {
370 + // This is a bit of a hack. We track the host root as a placement to
371 + // know that we're currently in a mounting state. That way isMounted
372 + // works as expected. We must reset this before committing.
373 + // TODO: Delete this when we delete isMounted and findDOMNode.
374 + workInProgress.effectTag |= Placement;
375 +
376 + // Ensure that children mount into this root without tracking
377 + // side-effects. This ensures that we don't store Placement effects on
378 + // nodes that will be hydrated.
379 + workInProgress.child = mountChildFibersInPlace(
380 + workInProgress,
381 + workInProgress.child,
382 + element,
383 + priorityLevel,
384 + );
385 + markChildAsProgressed(current, workInProgress, priorityLevel);
386 + return workInProgress.child;
387 + }
388 + }
389 + // Otherwise reset hydration state in case we aborted and resumed another
390 + // root.
391 + resetHydrationState();
392 reconcileChildren(current, workInProgress, element);
393 memoizeState(workInProgress, state);
394 return workInProgress.child;
395 }
396 + resetHydrationState();
397 // If there is no update queue, that's a bailout because the root has no props.
398 return bailoutOnAlreadyFinishedWork(current, workInProgress);
399 }
@@ -363,6 +401,10 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
401 function updateHostComponent(current, workInProgress) {
402 pushHostContext(workInProgress);
403
404 + if (current === null) {
405 + tryToClaimNextHydratableInstance(workInProgress);
406 + }
407 +
408 let nextProps = workInProgress.pendingProps;
409 const prevProps = current !== null ? current.memoizedProps : null;
410 const memoizedProps = workInProgress.memoizedProps;
@@ -471,6 +513,9 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
513 }
514
515 function updateHostText(current, workInProgress) {
516 + if (current === null) {
517 + tryToClaimNextHydratableInstance(workInProgress);
518 + }
519 let nextProps = workInProgress.pendingProps;
520 if (nextProps === null) {
521 nextProps = workInProgress.memoizedProps;
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+61 -26
@@ -15,6 +15,7 @@
15 import type {ReactCoroutine} from 'ReactTypes';
16 import type {Fiber} from 'ReactFiber';
17 import type {HostContext} from 'ReactFiberHostContext';
18 +import type {HydrationContext} from 'ReactFiberHydrationContext';
19 import type {FiberRoot} from 'ReactFiberRoot';
20 import type {HostConfig} from 'ReactFiberReconciler';
21
@@ -35,7 +36,7 @@ var {
36 YieldComponent,
37 Fragment,
38 } = ReactTypeOfWork;
38 -var {Ref, Update} = ReactTypeOfSideEffect;
39 +var {Placement, Ref, Update} = ReactTypeOfSideEffect;
40
41 if (__DEV__) {
42 var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
@@ -46,6 +47,7 @@ var invariant = require('fbjs/lib/invariant');
47 module.exports = function<T, P, I, TI, PI, C, CX, PL>(
48 config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
49 hostContext: HostContext<C, CX>,
50 + hydrationContext: HydrationContext<I, TI>,
51 ) {
52 const {
53 createInstance,
@@ -62,6 +64,12 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
64 popHostContainer,
65 } = hostContext;
66
67 + const {
68 + hydrateHostInstance,
69 + hydrateHostTextInstance,
70 + popHydrationState,
71 + } = hydrationContext;
72 +
73 function markChildAsProgressed(current, workInProgress, priorityLevel) {
74 // We now have clones. Let's store them as the currently progressed work.
75 workInProgress.progressedChild = workInProgress.child;
@@ -206,6 +214,15 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
214 fiberRoot.context = fiberRoot.pendingContext;
215 fiberRoot.pendingContext = null;
216 }
217 +
218 + if (current === null || current.child === null) {
219 + // If we hydrated, pop so that we can delete any remaining children
220 + // that weren't hydrated.
221 + popHydrationState(workInProgress);
222 + // This resets the hacky state to fix isMounted before committing.
223 + // TODO: Delete this when we delete isMounted and findDOMNode.
224 + workInProgress.effectTag &= ~Placement;
225 + }
226 return null;
227 }
228 case HostComponent: {
@@ -258,28 +275,37 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
275 // "stack" as the parent. Then append children as we go in beginWork
276 // or completeWork depending on we want to add then top->down or
277 // bottom->up. Top->down is faster in IE11.
261 - const instance = createInstance(
262 - type,
263 - newProps,
264 - rootContainerInstance,
265 - currentHostContext,
266 - workInProgress,
267 - );
268 -
269 - appendAllChildren(instance, workInProgress);
270 -
271 - // Certain renderers require commit-time effects for initial mount.
272 - // (eg DOM renderer supports auto-focus for certain elements).
273 - // Make sure such renderers get scheduled for later work.
274 - if (
275 - finalizeInitialChildren(
276 - instance,
278 + let instance;
279 + let wasHydrated = popHydrationState(workInProgress);
280 + if (wasHydrated) {
281 + instance = hydrateHostInstance(
282 + workInProgress,
283 + rootContainerInstance,
284 + );
285 + } else {
286 + instance = createInstance(
287 type,
288 newProps,
289 rootContainerInstance,
280 - )
281 - ) {
282 - markUpdate(workInProgress);
290 + currentHostContext,
291 + workInProgress,
292 + );
293 +
294 + appendAllChildren(instance, workInProgress);
295 +
296 + // Certain renderers require commit-time effects for initial mount.
297 + // (eg DOM renderer supports auto-focus for certain elements).
298 + // Make sure such renderers get scheduled for later work.
299 + if (
300 + finalizeInitialChildren(
301 + instance,
302 + type,
303 + newProps,
304 + rootContainerInstance,
305 + )
306 + ) {
307 + markUpdate(workInProgress);
308 + }
309 }
310
311 workInProgress.stateNode = instance;
@@ -311,12 +337,21 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
337 }
338 const rootContainerInstance = getRootHostContainer();
339 const currentHostContext = getHostContext();
314 - const textInstance = createTextInstance(
315 - newText,
316 - rootContainerInstance,
317 - currentHostContext,
318 - workInProgress,
319 - );
340 + let textInstance;
341 + let wasHydrated = popHydrationState(workInProgress);
342 + if (wasHydrated) {
343 + textInstance = hydrateHostTextInstance(
344 + workInProgress,
345 + rootContainerInstance,
346 + );
347 + } else {
348 + textInstance = createTextInstance(
349 + newText,
350 + rootContainerInstance,
351 + currentHostContext,
352 + workInProgress,
353 + );
354 + }
355 workInProgress.stateNode = textInstance;
356 }
357 return null;
src/renderers/shared/fiber/ReactFiberHydrationContext.js new
+234
@@ -0,0 +1,234 @@
1 +/**
2 + * Copyright 2013-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactFiberHydrationContext
10 + * @flow
11 + */
12 +
13 +'use strict';
14 +
15 +import type {Fiber} from 'ReactFiber';
16 +import type {HostConfig} from 'ReactFiberReconciler';
17 +
18 +var invariant = require('fbjs/lib/invariant');
19 +
20 +const {HostComponent, HostRoot} = require('ReactTypeOfWork');
21 +const {Deletion, Placement} = require('ReactTypeOfSideEffect');
22 +
23 +const {createFiberFromHostInstanceForDeletion} = require('ReactFiber');
24 +
25 +export type HydrationContext<I, TI> = {
26 + enterHydrationState(fiber: Fiber): boolean,
27 + resetHydrationState(): void,
28 + tryToClaimNextHydratableInstance(fiber: Fiber): void,
29 + hydrateHostInstance(fiber: Fiber): I,
30 + hydrateHostTextInstance(fiber: Fiber): TI,
31 + popHydrationState(fiber: Fiber): boolean,
32 +};
33 +
34 +module.exports = function<T, P, I, TI, PI, C, CX, PL>(
35 + config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
36 +): HydrationContext<I, TI> {
37 + const {
38 + shouldSetTextContent,
39 + canHydrateInstance,
40 + canHydrateTextInstance,
41 + getNextHydratableSibling,
42 + getFirstHydratableChild,
43 + hydrateInstance,
44 + hydrateTextInstance,
45 + } = config;
46 +
47 + // If this doesn't have hydration mode.
48 + if (
49 + !(canHydrateInstance &&
50 + canHydrateTextInstance &&
51 + getNextHydratableSibling &&
52 + getFirstHydratableChild &&
53 + hydrateInstance &&
54 + hydrateTextInstance)
55 + ) {
56 + return {
57 + enterHydrationState() {
58 + return false;
59 + },
60 + resetHydrationState() {},
61 + tryToClaimNextHydratableInstance() {},
62 + hydrateHostInstance() {
63 + invariant(false, 'React bug.');
64 + },
65 + hydrateHostTextInstance() {
66 + invariant(false, 'React bug.');
67 + },
68 + popHydrationState(fiber: Fiber) {
69 + return false;
70 + },
71 + };
72 + }
73 +
74 + // The deepest Fiber on the stack involved in a hydration context.
75 + // This may have been an insertion or a hydration.
76 + let hydrationParentFiber: null | Fiber = null;
77 + let nextHydratableInstance: null | I | TI = null;
78 + let isHydrating: boolean = false;
79 +
80 + function enterHydrationState(fiber: Fiber) {
81 + const parentInstance = fiber.stateNode.containerInfo;
82 + nextHydratableInstance = getFirstHydratableChild(parentInstance);
83 + hydrationParentFiber = fiber;
84 + isHydrating = true;
85 + return true;
86 + }
87 +
88 + function deleteHydratableInstance(returnFiber: Fiber, instance: I | TI) {
89 + const childToDelete = createFiberFromHostInstanceForDeletion();
90 + childToDelete.stateNode = instance;
91 + childToDelete.return = returnFiber;
92 + // Deletions are added in reversed order so we add it to the front.
93 + const last = returnFiber.progressedLastDeletion;
94 + if (last !== null) {
95 + last.nextEffect = childToDelete;
96 + returnFiber.progressedLastDeletion = childToDelete;
97 + } else {
98 + returnFiber.progressedFirstDeletion = returnFiber.progressedLastDeletion = childToDelete;
99 + }
100 + childToDelete.effectTag = Deletion;
101 +
102 + if (returnFiber.lastEffect !== null) {
103 + returnFiber.lastEffect.nextEffect = childToDelete;
104 + returnFiber.lastEffect = childToDelete;
105 + } else {
106 + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
107 + }
108 + }
109 +
110 + function tryToClaimNextHydratableInstance(fiber: Fiber) {
111 + if (!isHydrating) {
112 + return;
113 + }
114 + let nextInstance = nextHydratableInstance;
115 + if (!nextInstance) {
116 + // Nothing to hydrate. Make it an insertion.
117 + fiber.effectTag |= Placement;
118 + isHydrating = false;
119 + hydrationParentFiber = fiber;
120 + return;
121 + }
122 + const type = fiber.type;
123 + const props = fiber.memoizedProps;
124 + if (!canHydrateInstance(nextInstance, type, props)) {
125 + // If we can't hydrate this instance let's try the next one.
126 + // We use this as a heuristic. It's based on intuition and not data so it
127 + // might be flawed or unnecessary.
128 + nextInstance = getNextHydratableSibling(nextInstance);
129 + if (!nextInstance || !canHydrateInstance(nextInstance, type, props)) {
130 + // Nothing to hydrate. Make it an insertion.
131 + fiber.effectTag |= Placement;
132 + isHydrating = false;
133 + hydrationParentFiber = fiber;
134 + return;
135 + }
136 + // We matched the next one, we'll now assume that the first one was
137 + // superfluous and we'll delete it. Since we can't eagerly delete it
138 + // we'll have to schedule a deletion. To do that, this node needs a dummy
139 + // fiber associated with it.
140 + deleteHydratableInstance(
141 + (hydrationParentFiber: any),
142 + nextHydratableInstance,
143 + );
144 + }
145 + fiber.stateNode = nextInstance;
146 + hydrationParentFiber = fiber;
147 + nextHydratableInstance = getFirstHydratableChild(nextInstance);
148 + }
149 +
150 + function hydrateHostInstance(fiber: Fiber, rootContainerInstance: any): I {
151 + const instance: I = fiber.stateNode;
152 + hydrateInstance(
153 + instance,
154 + fiber.type,
155 + fiber.memoizedProps,
156 + rootContainerInstance,
157 + fiber,
158 + );
159 + return instance;
160 + }
161 +
162 + function hydrateHostTextInstance(fiber: Fiber): TI {
163 + const textInstance: TI = fiber.stateNode;
164 + hydrateTextInstance(textInstance, fiber);
165 + return textInstance;
166 + }
167 +
168 + function popToNextHostParent(fiber: Fiber): void {
169 + let parent = fiber.return;
170 + while (
171 + parent !== null &&
172 + parent.tag !== HostComponent &&
173 + parent.tag !== HostRoot
174 + ) {
175 + parent = parent.return;
176 + }
177 + hydrationParentFiber = parent;
178 + }
179 +
180 + function popHydrationState(fiber: Fiber): boolean {
181 + if (fiber !== hydrationParentFiber) {
182 + // We're deeper than the current hydration context, inside an inserted
183 + // tree.
184 + return false;
185 + }
186 + if (!isHydrating) {
187 + // If we're not currently hydrating but we're in a hydration context, then
188 + // we were an insertion and now need to pop up reenter hydration of our
189 + // siblings.
190 + popToNextHostParent(fiber);
191 + isHydrating = true;
192 + return false;
193 + }
194 +
195 + // If we have any remaining hydratable nodes, we need to delete them now.
196 + // We only do this deeper than head and body since they tend to have random
197 + // other nodes in them. We also ignore components with pure text content in
198 + // side of them.
199 + // TODO: Better heuristic.
200 + if (
201 + fiber.tag !== HostComponent ||
202 + (fiber.type !== 'head' &&
203 + fiber.type !== 'body' &&
204 + !shouldSetTextContent(fiber.memoizedProps))
205 + ) {
206 + let nextInstance = nextHydratableInstance;
207 + while (nextInstance) {
208 + deleteHydratableInstance(fiber, nextInstance);
209 + nextInstance = getNextHydratableSibling(nextInstance);
210 + }
211 + }
212 +
213 + popToNextHostParent(fiber);
214 + nextHydratableInstance = hydrationParentFiber
215 + ? getNextHydratableSibling(fiber.stateNode)
216 + : null;
217 + return true;
218 + }
219 +
220 + function resetHydrationState() {
221 + hydrationParentFiber = null;
222 + nextHydratableInstance = null;
223 + isHydrating = false;
224 + }
225 +
226 + return {
227 + enterHydrationState,
228 + resetHydrationState,
229 + tryToClaimNextHydratableInstance,
230 + hydrateHostInstance,
231 + hydrateHostTextInstance,
232 + popHydrationState,
233 + };
234 +};
src/renderers/shared/fiber/ReactFiberReconciler.js
+17
@@ -114,6 +114,23 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
114 prepareForCommit(): void,
115 resetAfterCommit(): void,
116
117 + // Optional hydration
118 + canHydrateInstance?: (instance: I | TI, type: T, props: P) => boolean,
119 + canHydrateTextInstance?: (instance: I | TI) => boolean,
120 + getNextHydratableSibling?: (instance: I | TI) => null | I | TI,
121 + getFirstHydratableChild?: (parentInstance: C | I) => null | I | TI,
122 + hydrateInstance?: (
123 + instance: I,
124 + type: T,
125 + props: P,
126 + rootContainerInstance: C,
127 + internalInstanceHandle: OpaqueHandle,
128 + ) => void,
129 + hydrateTextInstance?: (
130 + textInstance: TI,
131 + internalInstanceHandle: OpaqueHandle,
132 + ) => void,
133 +
134 useSyncScheduling?: boolean,
135 };
136
src/renderers/shared/fiber/ReactFiberScheduler.js
+11 -1
@@ -16,6 +16,7 @@ import type {Fiber} from 'ReactFiber';
16 import type {FiberRoot} from 'ReactFiberRoot';
17 import type {HostConfig, Deadline} from 'ReactFiberReconciler';
18 import type {PriorityLevel} from 'ReactPriorityLevel';
19 +import type {HydrationContext} from 'ReactFiberHydrationContext';
20
21 export type CapturedError = {
22 componentName: ?string,
@@ -43,6 +44,7 @@ var ReactFiberBeginWork = require('ReactFiberBeginWork');
44 var ReactFiberCompleteWork = require('ReactFiberCompleteWork');
45 var ReactFiberCommitWork = require('ReactFiberCommitWork');
46 var ReactFiberHostContext = require('ReactFiberHostContext');
47 +var ReactFiberHydrationContext = require('ReactFiberHydrationContext');
48 var ReactFeatureFlags = require('ReactFeatureFlags');
49 var {ReactCurrentOwner} = require('ReactGlobalSharedState');
50 var getComponentName = require('getComponentName');
@@ -145,14 +147,22 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
147 config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
148 ) {
149 const hostContext = ReactFiberHostContext(config);
150 + const hydrationContext: HydrationContext<I, TI> = ReactFiberHydrationContext(
151 + config,
152 + );
153 const {popHostContainer, popHostContext, resetHostContainer} = hostContext;
154 const {beginWork, beginFailedWork} = ReactFiberBeginWork(
155 config,
156 hostContext,
157 + hydrationContext,
158 scheduleUpdate,
159 getPriorityContext,
160 );
155 - const {completeWork} = ReactFiberCompleteWork(config, hostContext);
161 + const {completeWork} = ReactFiberCompleteWork(
162 + config,
163 + hostContext,
164 + hydrationContext,
165 + );
166 const {
167 commitPlacement,
168 commitDeletion,
src/test/getTestDocument.js
+5 -4
@@ -12,13 +12,14 @@
12 'use strict';
13
14 function getTestDocument(markup) {
15 - document.open();
16 - document.write(
15 + var doc = document.implementation.createHTMLDocument('');
16 + doc.open();
17 + doc.write(
18 markup ||
19 '<!doctype html><html><meta charset=utf-8><title>test doc</title>',
20 );
20 - document.close();
21 - return document;
21 + doc.close();
22 + return doc;
23 }
24
25 module.exports = getTestDocument;