@@ -279,6 +279,8 @@ function validateFragmentProps(fragment) {
279279  } 
280280} 
281281
282+ const  didWarnAboutKeySpread  =  { } ; 
283+ 
282284export  function  jsxWithValidation ( 
283285  type , 
284286  props , 
@@ -287,115 +289,132 @@ export function jsxWithValidation(
287289  source , 
288290  self , 
289291)  { 
290-   const  validType  =  isValidElementType ( type ) ; 
291- 
292-   // We warn in this case but don't throw. We expect the element creation to 
293-   // succeed and there will likely be errors in render. 
294-   if  ( ! validType )  { 
295-     let  info  =  '' ; 
296-     if  ( 
297-       type  ===  undefined  || 
298-       ( typeof  type  ===  'object'  && 
299-         type  !==  null  && 
300-         Object . keys ( type ) . length  ===  0 ) 
301-     )  { 
302-       info  += 
303-         ' You likely forgot to export your component from the file '  + 
304-         "it's defined in, or you might have mixed up default and named imports." ; 
305-     } 
292+   if  ( __DEV__ )  { 
293+     const  validType  =  isValidElementType ( type ) ; 
294+ 
295+     // We warn in this case but don't throw. We expect the element creation to 
296+     // succeed and there will likely be errors in render. 
297+     if  ( ! validType )  { 
298+       let  info  =  '' ; 
299+       if  ( 
300+         type  ===  undefined  || 
301+         ( typeof  type  ===  'object'  && 
302+           type  !==  null  && 
303+           Object . keys ( type ) . length  ===  0 ) 
304+       )  { 
305+         info  += 
306+           ' You likely forgot to export your component from the file '  + 
307+           "it's defined in, or you might have mixed up default and named imports." ; 
308+       } 
306309
307-     const  sourceInfo  =  getSourceInfoErrorAddendum ( source ) ; 
308-     if  ( sourceInfo )  { 
309-       info  +=  sourceInfo ; 
310-     }  else  { 
311-       info  +=  getDeclarationErrorAddendum ( ) ; 
312-     } 
310+        const  sourceInfo  =  getSourceInfoErrorAddendum ( source ) ; 
311+        if  ( sourceInfo )  { 
312+          info  +=  sourceInfo ; 
313+        }  else  { 
314+          info  +=  getDeclarationErrorAddendum ( ) ; 
315+        } 
313316
314-     let  typeString ; 
315-     if  ( type  ===  null )  { 
316-       typeString  =  'null' ; 
317-     }  else  if  ( isArray ( type ) )  { 
318-       typeString  =  'array' ; 
319-     }  else  if  ( type  !==  undefined  &&  type . $$typeof  ===  REACT_ELEMENT_TYPE )  { 
320-       typeString  =  `<${ getComponentNameFromType ( type . type )  ||  'Unknown' }   />` ; 
321-       info  = 
322-         ' Did you accidentally export a JSX literal instead of a component?' ; 
323-     }  else  { 
324-       typeString  =  typeof  type ; 
325-     } 
317+        let  typeString ; 
318+        if  ( type  ===  null )  { 
319+          typeString  =  'null' ; 
320+        }  else  if  ( isArray ( type ) )  { 
321+          typeString  =  'array' ; 
322+        }  else  if  ( type  !==  undefined  &&  type . $$typeof  ===  REACT_ELEMENT_TYPE )  { 
323+          typeString  =  `<${ getComponentNameFromType ( type . type )  ||  'Unknown' }   />` ; 
324+          info  = 
325+            ' Did you accidentally export a JSX literal instead of a component?' ; 
326+        }  else  { 
327+          typeString  =  typeof  type ; 
328+        } 
326329
327-     if  ( __DEV__ )  { 
328-       console . error ( 
329-         'React.jsx: type is invalid -- expected a string (for '  + 
330-           'built-in components) or a class/function (for composite '  + 
331-           'components) but got: %s.%s' , 
332-         typeString , 
333-         info , 
334-       ) ; 
330+       if  ( __DEV__ )  { 
331+         console . error ( 
332+           'React.jsx: type is invalid -- expected a string (for '  + 
333+             'built-in components) or a class/function (for composite '  + 
334+             'components) but got: %s.%s' , 
335+           typeString , 
336+           info , 
337+         ) ; 
338+       } 
335339    } 
336-   } 
337340
338-   const  element  =  jsxDEV ( type ,  props ,  key ,  source ,  self ) ; 
339- 
340-   // The result can be nullish if a mock or a custom function is used. 
341-   // TODO: Drop this when these are no longer allowed as the type argument. 
342-   if  ( element  ==  null )  { 
343-     return  element ; 
344-   } 
345- 
346-   // Skip key warning if the type isn't valid since our key validation logic 
347-   // doesn't expect a non-string/function type and can throw confusing errors. 
348-   // We don't want exception behavior to differ between dev and prod. 
349-   // (Rendering will throw with a helpful message and as soon as the type is 
350-   // fixed, the key warnings will appear.) 
341+     const  element  =  jsxDEV ( type ,  props ,  key ,  source ,  self ) ; 
351342
352-   if  ( validType )  { 
353-     const  children  =  props . children ; 
354-     if  ( children  !==  undefined )  { 
355-       if  ( isStaticChildren )  { 
356-         if  ( isArray ( children ) )  { 
357-           for  ( let  i  =  0 ;  i  <  children . length ;  i ++ )  { 
358-             validateChildKeys ( children [ i ] ,  type ) ; 
359-           } 
343+     // The result can be nullish if a mock or a custom function is used. 
344+     // TODO: Drop this when these are no longer allowed as the type argument. 
345+     if  ( element  ==  null )  { 
346+       return  element ; 
347+     } 
360348
361-           if  ( Object . freeze )  { 
362-             Object . freeze ( children ) ; 
349+     // Skip key warning if the type isn't valid since our key validation logic 
350+     // doesn't expect a non-string/function type and can throw confusing errors. 
351+     // We don't want exception behavior to differ between dev and prod. 
352+     // (Rendering will throw with a helpful message and as soon as the type is 
353+     // fixed, the key warnings will appear.) 
354+ 
355+     if  ( validType )  { 
356+       const  children  =  props . children ; 
357+       if  ( children  !==  undefined )  { 
358+         if  ( isStaticChildren )  { 
359+           if  ( isArray ( children ) )  { 
360+             for  ( let  i  =  0 ;  i  <  children . length ;  i ++ )  { 
361+               validateChildKeys ( children [ i ] ,  type ) ; 
362+             } 
363+ 
364+             if  ( Object . freeze )  { 
365+               Object . freeze ( children ) ; 
366+             } 
367+           }  else  { 
368+             if  ( __DEV__ )  { 
369+               console . error ( 
370+                 'React.jsx: Static children should always be an array. '  + 
371+                   'You are likely explicitly calling React.jsxs or React.jsxDEV. '  + 
372+                   'Use the Babel transform instead.' , 
373+               ) ; 
374+             } 
363375          } 
364376        }  else  { 
365-           if  ( __DEV__ )  { 
366-             console . error ( 
367-               'React.jsx: Static children should always be an array. '  + 
368-                 'You are likely explicitly calling React.jsxs or React.jsxDEV. '  + 
369-                 'Use the Babel transform instead.' , 
370-             ) ; 
371-           } 
377+           validateChildKeys ( children ,  type ) ; 
372378        } 
373-       }  else  { 
374-         validateChildKeys ( children ,  type ) ; 
375379      } 
376380    } 
377-   } 
378381
379-   if  ( __DEV__ )  { 
380382    if  ( warnAboutSpreadingKeyToJSX )  { 
381383      if  ( hasOwnProperty . call ( props ,  'key' ) )  { 
382-         console . error ( 
383-           'React.jsx: Spreading a key to JSX is a deprecated pattern. '  + 
384-             'Explicitly pass a key after spreading props in your JSX call. '  + 
385-             'E.g. <%s {...props} key={key} />' , 
386-           getComponentNameFromType ( type )  ||  'ComponentName' , 
387-         ) ; 
384+         const  componentName  =  getComponentNameFromType ( type ) ; 
385+         const  keys  =  Object . keys ( props ) . filter ( k  =>  k  !==  'key' ) ; 
386+         const  beforeExample  = 
387+           keys . length  >  0 
388+             ? '{key: someKey, '  +  keys . join ( ': ..., ' )  +  ': ...}' 
389+             : '{key: someKey}' ; 
390+         if  ( ! didWarnAboutKeySpread [ componentName  +  beforeExample ] )  { 
391+           const  afterExample  = 
392+             keys . length  >  0  ? '{'  +  keys . join ( ': ..., ' )  +  ': ...}'  : '{}' ; 
393+           console . error ( 
394+             'A props object containing a "key" prop is being spread into JSX:\n'  + 
395+               '  let props = %s;\n'  + 
396+               '  <%s {...props} />\n'  + 
397+               'React keys must be passed directly to JSX without using spread:\n'  + 
398+               '  let props = %s;\n'  + 
399+               '  <%s key={someKey} {...props} />' , 
400+             beforeExample , 
401+             componentName , 
402+             afterExample , 
403+             componentName , 
404+           ) ; 
405+           didWarnAboutKeySpread [ componentName  +  beforeExample ]  =  true ; 
406+         } 
388407      } 
389408    } 
390-   } 
391409
392-   if  ( type  ===  REACT_FRAGMENT_TYPE )  { 
393-     validateFragmentProps ( element ) ; 
394-   }  else  { 
395-     validatePropTypes ( element ) ; 
396-   } 
410+      if  ( type  ===  REACT_FRAGMENT_TYPE )  { 
411+        validateFragmentProps ( element ) ; 
412+      }  else  { 
413+        validatePropTypes ( element ) ; 
414+      } 
397415
398-   return  element ; 
416+     return  element ; 
417+   } 
399418} 
400419
401420// These two functions exist to still get child warnings in dev 
0 commit comments