1313
1414var ReactElement = require ( 'ReactElement' ) ;
1515
16+ var invariant = require ( 'invariant' ) ;
17+ var traverseAllChildren = require ( 'traverseAllChildren' ) ;
1618var warning = require ( 'warning' ) ;
1719
1820/**
1921 * We used to allow keyed objects to serve as a collection of ReactElements,
2022 * or nested sets. This allowed us a way to explicitly key a set a fragment of
2123 * components. This is now being replaced with an opaque data structure.
2224 * The upgrade path is to call React.addons.createFragment({ key: value }) to
23- * create a keyed fragment. The resulting data structure is opaque, for now .
25+ * create a keyed fragment. The resulting data structure is an array .
2426 */
2527
26- var fragmentKey ;
27- var didWarnKey ;
28- var canWarnForReactFragment ;
28+ var numericPropertyRegex = / ^ \d + $ / ;
2929
30- if ( __DEV__ ) {
31- fragmentKey = '_reactFragment' ;
32- didWarnKey = '_reactDidWarn' ;
33-
34- try {
35- // Feature test. Don't even try to issue this warning if we can't use
36- // enumerable: false.
37-
38- var dummy = function ( ) {
39- return 1 ;
40- } ;
41-
42- Object . defineProperty (
43- { } ,
44- fragmentKey ,
45- { enumerable : false , value : true }
46- ) ;
47-
48- Object . defineProperty (
49- { } ,
50- 'key' ,
51- { enumerable : true , get : dummy }
52- ) ;
30+ var userProvidedKeyEscapeRegex = / \/ / g;
31+ function escapeUserProvidedKey ( text ) {
32+ return ( '' + text ) . replace ( userProvidedKeyEscapeRegex , '//' ) ;
33+ }
5334
54- canWarnForReactFragment = true ;
55- } catch ( x ) {
56- canWarnForReactFragment = false ;
35+ function processSingleChildWithContext ( ctx , child , childKey ) {
36+ if ( ReactElement . isValidElement ( child ) ) {
37+ child = ReactElement . cloneAndReplaceKey ( child , ctx . prefix + childKey ) ;
5738 }
58-
59- var proxyPropertyAccessWithWarning = function ( obj , key ) {
60- Object . defineProperty ( obj , key , {
61- enumerable : true ,
62- get : function ( ) {
63- warning (
64- this [ didWarnKey ] ,
65- 'A ReactFragment is an opaque type. Accessing any of its ' +
66- 'properties is deprecated. Pass it to one of the React.Children ' +
67- 'helpers.'
68- ) ;
69- this [ didWarnKey ] = true ;
70- return this [ fragmentKey ] [ key ] ;
71- } ,
72- set : function ( value ) {
73- warning (
74- this [ didWarnKey ] ,
75- 'A ReactFragment is an immutable opaque type. Mutating its ' +
76- 'properties is deprecated.'
77- ) ;
78- this [ didWarnKey ] = true ;
79- this [ fragmentKey ] [ key ] = value ;
80- } ,
81- } ) ;
82- } ;
83-
84- var issuedWarnings = { } ;
85-
86- var getFragmentKeyString = function ( fragment ) {
87- var fragmentCacheKey = '' ;
88- for ( var key in fragment ) {
89- fragmentCacheKey += key + ':' + ( typeof fragment [ key ] ) + ',' ;
90- }
91- return fragmentCacheKey ;
92- } ;
93-
94- var didWarnForFragment = function ( fragmentCacheKey ) {
95- // We use the keys and the type of the value as a heuristic to dedupe the
96- // warning to avoid spamming too much.
97- var alreadyWarnedOnce = ! ! issuedWarnings [ fragmentCacheKey ] ;
98- issuedWarnings [ fragmentCacheKey ] = true ;
99- return alreadyWarnedOnce ;
100- } ;
39+ // For text components, leave unkeyed
40+ ctx . result . push ( child ) ;
10141}
10242
43+ var warnedAboutNumeric = false ;
44+
10345var ReactFragment = {
10446 // Wrap a keyed object in an opaque proxy that warns you if you access any
10547 // of its properties.
@@ -121,71 +63,35 @@ var ReactFragment = {
12163 ) ;
12264 return object ;
12365 }
124- if ( canWarnForReactFragment ) {
125- var proxy = { } ;
126- Object . defineProperty ( proxy , fragmentKey , {
127- enumerable : false ,
128- value : object ,
129- } ) ;
130- Object . defineProperty ( proxy , didWarnKey , {
131- writable : true ,
132- enumerable : false ,
133- value : false ,
134- } ) ;
135- for ( var key in object ) {
136- proxyPropertyAccessWithWarning ( proxy , key ) ;
137- }
138- Object . preventExtensions ( proxy ) ;
139- return proxy ;
140- }
14166 }
142- return object ;
143- } ,
144- // Extract the original keyed object from the fragment opaque type. Warn if
145- // a plain object is passed here.
146- extract : function ( fragment ) {
147- if ( __DEV__ ) {
148- if ( canWarnForReactFragment ) {
149- if ( ! fragment [ fragmentKey ] ) {
150- var fragmentKeys = getFragmentKeyString ( fragment ) ;
67+ invariant (
68+ object . nodeType !== 1 ,
69+ 'React.addons.createFragment(...): Encountered an invalid child; DOM ' +
70+ 'elements are not valid children of React components.'
71+ ) ;
72+
73+ var result = [ ] ;
74+ var context = {
75+ result : result ,
76+ prefix : '' ,
77+ } ;
78+
79+ for ( var key in object ) {
80+ if ( __DEV__ ) {
81+ if ( ! warnedAboutNumeric && numericPropertyRegex . test ( key ) ) {
15182 warning (
152- didWarnForFragment ( fragmentKeys ) ,
153- 'Any use of a keyed object should be wrapped in ' +
154- 'React.addons.createFragment(object) before being passed as a ' +
155- 'child. {%s}' ,
156- fragmentKeys
83+ false ,
84+ 'React.addons.createFragment(...): Child objects should have ' +
85+ 'non-numeric keys so ordering is preserved.'
15786 ) ;
158- return fragment ;
159- }
160- return fragment [ fragmentKey ] ;
161- }
162- }
163- return fragment ;
164- } ,
165- // Check if this is a fragment and if so, extract the keyed object. If it
166- // is a fragment-like object, warn that it should be wrapped. Ignore if we
167- // can't determine what kind of object this is.
168- extractIfFragment : function ( fragment ) {
169- if ( __DEV__ ) {
170- if ( canWarnForReactFragment ) {
171- // If it is the opaque type, return the keyed object.
172- if ( fragment [ fragmentKey ] ) {
173- return fragment [ fragmentKey ] ;
174- }
175- // Otherwise, check each property if it has an element, if it does
176- // it is probably meant as a fragment, so we can warn early. Defer,
177- // the warning to extract.
178- for ( var key in fragment ) {
179- if ( fragment . hasOwnProperty ( key ) &&
180- ReactElement . isValidElement ( fragment [ key ] ) ) {
181- // This looks like a fragment object, we should provide an
182- // early warning.
183- return ReactFragment . extract ( fragment ) ;
184- }
87+ warnedAboutNumeric = true ;
18588 }
18689 }
90+ context . prefix = escapeUserProvidedKey ( key ) + '/' ;
91+ traverseAllChildren ( object [ key ] , processSingleChildWithContext , context ) ;
18792 }
188- return fragment ;
93+
94+ return result ;
18995 } ,
19096} ;
19197
0 commit comments