@@ -325,13 +325,16 @@ function isAsyncFunction(fn) {
325325// in the element tree before passing to React's client-side renderer.
326326// This replicates the implicit use() behavior that React's server renderer
327327// provides for async components but which the client renderer does not support.
328+ // Walks all props (not just children) so async components passed as e.g.
329+ // sidebar, fallback, or header props are also resolved.
328330async function resolveElement ( element ) {
329331 if ( element == null || typeof element !== 'object' ) {
330332 return element
331333 }
332334
333335 if ( Array . isArray ( element ) ) {
334- return Promise . all ( element . map ( resolveElement ) )
336+ const resolved = await Promise . all ( element . map ( resolveElement ) )
337+ return resolved . some ( ( r , i ) => r !== element [ i ] ) ? resolved : element
335338 }
336339
337340 if ( ! React . isValidElement ( element ) ) {
@@ -343,21 +346,64 @@ async function resolveElement(element) {
343346 return resolveElement ( resolved )
344347 }
345348
346- const children = element . props ?. children
347- if ( children == null ) {
349+ return resolveElementProps ( element )
350+ }
351+
352+ async function resolveElementProps ( element ) {
353+ const props = element . props
354+ if ( props == null ) {
348355 return element
349356 }
350357
351- const resolvedChildren = await resolveElement ( children )
358+ let propsChanged = false
359+ let childrenChanged = false
360+ const newProps = { }
361+ let resolvedChildren
362+
363+ for ( const key of Object . keys ( props ) ) {
364+ const value = props [ key ]
365+
366+ if ( key === 'children' ) {
367+ resolvedChildren = await resolveElement ( value )
368+ childrenChanged = resolvedChildren !== value
369+ continue
370+ }
371+
372+ // Only resolve values that are React elements to avoid inadvertently
373+ // awaiting Promise-valued props (e.g. dataPromise for use())
374+ if ( React . isValidElement ( value ) ) {
375+ const resolved = await resolveElement ( value )
376+ newProps [ key ] = resolved
377+ if ( resolved !== value ) {
378+ propsChanged = true
379+ }
380+ } else {
381+ newProps [ key ] = value
382+ }
383+ }
352384
353- if ( resolvedChildren === children ) {
385+ if ( ! propsChanged && ! childrenChanged ) {
354386 return element
355387 }
356388
357- if ( Array . isArray ( resolvedChildren ) ) {
358- return React . cloneElement ( element , undefined , ...resolvedChildren )
389+ // Spread children as separate arguments to cloneElement to preserve
390+ // positional identity and avoid "missing key" warnings
391+ if ( childrenChanged ) {
392+ if ( Array . isArray ( resolvedChildren ) ) {
393+ return React . cloneElement (
394+ element ,
395+ propsChanged ? newProps : undefined ,
396+ ...resolvedChildren ,
397+ )
398+ }
399+ return React . cloneElement (
400+ element ,
401+ propsChanged ? newProps : undefined ,
402+ resolvedChildren ,
403+ )
359404 }
360- return React . cloneElement ( element , undefined , resolvedChildren )
405+
406+ return React . cloneElement ( element , newProps )
361407}
362408
363409async function renderAsync ( ui , options ) {
0 commit comments