@@ -732,8 +732,32 @@ function createElement(
732
732
// This is effectively the complete phase.
733
733
initializingHandler = handler . parent ;
734
734
if ( handler . errored ) {
735
- // TODO: Encode the error as Lazy.
736
- throw handler . value ;
735
+ // Something errored inside this Element's props. We can turn this Element
736
+ // into a Lazy so that we can still render up until that Lazy is rendered.
737
+ const erroredChunk : ErroredChunk < React$Element < any >> = createErrorChunk (
738
+ response ,
739
+ handler . value ,
740
+ ) ;
741
+ if ( __DEV__ ) {
742
+ // Conceptually the error happened inside this Element but right before
743
+ // it was rendered. We don't have a client side component to render but
744
+ // we can add some DebugInfo to explain that this was conceptually a
745
+ // Server side error that errored inside this element. That way any stack
746
+ // traces will point to the nearest JSX that errored - e.g. during
747
+ // serialization.
748
+ const erroredComponent : ReactComponentInfo = {
749
+ name : getComponentNameFromType ( element . type ) || '' ,
750
+ owner : element . _owner ,
751
+ } ;
752
+ if ( enableOwnerStacks ) {
753
+ // $FlowFixMe[cannot-write]
754
+ erroredComponent . stack = element . _debugStack ;
755
+ // $FlowFixMe[cannot-write]
756
+ erroredComponent . task = element . _debugTask ;
757
+ }
758
+ erroredChunk . _debugInfo = [ erroredComponent ] ;
759
+ }
760
+ return createLazyChunkWrapper(erroredChunk);
737
761
}
738
762
if ( handler . deps > 0 ) {
739
763
// We have blocked references inside this Element but we can turn this into
@@ -861,12 +885,43 @@ function waitForReference<T>(
861
885
// Promise.all.
862
886
return ;
863
887
}
888
+ const blockedValue = handler . value ;
864
889
handler . errored = true ;
865
890
handler . value = error ;
866
891
const chunk = handler . chunk ;
867
892
if ( chunk === null || chunk . status !== BLOCKED ) {
868
893
return ;
869
894
}
895
+
896
+ if ( __DEV__ ) {
897
+ if (
898
+ typeof blockedValue === 'object' &&
899
+ blockedValue !== null &&
900
+ blockedValue . $$typeof === REACT_ELEMENT_TYPE
901
+ ) {
902
+ const element = blockedValue ;
903
+ // Conceptually the error happened inside this Element but right before
904
+ // it was rendered. We don't have a client side component to render but
905
+ // we can add some DebugInfo to explain that this was conceptually a
906
+ // Server side error that errored inside this element. That way any stack
907
+ // traces will point to the nearest JSX that errored - e.g. during
908
+ // serialization.
909
+ const erroredComponent : ReactComponentInfo = {
910
+ name : getComponentNameFromType ( element . type ) || '' ,
911
+ owner : element . _owner ,
912
+ } ;
913
+ if ( enableOwnerStacks ) {
914
+ // $FlowFixMe[cannot-write]
915
+ erroredComponent . stack = element . _debugStack ;
916
+ // $FlowFixMe[cannot-write]
917
+ erroredComponent . task = element . _debugTask ;
918
+ }
919
+ const chunkDebugInfo : ReactDebugInfo =
920
+ chunk . _debugInfo || ( chunk . _debugInfo = [ ] ) ;
921
+ chunkDebugInfo . push ( erroredComponent ) ;
922
+ }
923
+ }
924
+
870
925
triggerErrorOnChunk ( chunk , error ) ;
871
926
}
872
927
@@ -961,7 +1016,22 @@ function getOutlinedModel<T>(
961
1016
case BLOCKED :
962
1017
return waitForReference ( chunk , parentObject , key , response , map , path ) ;
963
1018
default :
964
- throw chunk . reason ;
1019
+ // This is an error. Instead of erroring directly, we're going to encode this on
1020
+ // an initialization handler so that we can catch it at the nearest Element.
1021
+ if ( initializingHandler ) {
1022
+ initializingHandler . errored = true ;
1023
+ initializingHandler . value = chunk . reason ;
1024
+ } else {
1025
+ initializingHandler = {
1026
+ parent : null ,
1027
+ chunk : null ,
1028
+ value : chunk . reason ,
1029
+ deps : 0 ,
1030
+ errored : true ,
1031
+ } ;
1032
+ }
1033
+ // Placeholder
1034
+ return (null: any);
965
1035
}
966
1036
}
967
1037
0 commit comments