@@ -695,6 +695,7 @@ class ReactDOMServerRenderer {
695695 contextIndex: number;
696696 contextStack: Array< ReactContext < any > > ;
697697 contextValueStack: Array < any > ;
698+ contextValueMap: Map < ReactContext < any > , any > ;
698699 contextProviderStack: ?Array < ReactProvider < any >> ; // DEV-only
699700
700701 constructor ( children : mixed , makeStaticMarkup : boolean ) {
@@ -723,6 +724,7 @@ class ReactDOMServerRenderer {
723724 this . contextIndex = - 1 ;
724725 this . contextStack = [ ] ;
725726 this . contextValueStack = [ ] ;
727+ this . contextValueMap = new Map ( ) ;
726728 if ( __DEV__ ) {
727729 this . contextProviderStack = [ ] ;
728730 }
@@ -736,12 +738,21 @@ class ReactDOMServerRenderer {
736738 * we mutated it, onto the stacks. Therefore, on the way up, we always know which
737739 * provider needs to be "restored" to which value.
738740 * https://github.com/facebook/react/pull/12985#issuecomment-396301248
741+ *
742+ * A context's _currentValue is not directly mutated to avoid issues with
743+ * concurrent renderers. Instead a local contextValueMap stores the current
744+ * value for each context instance.
739745 */
740746
741747 pushProvider < T > ( provider : ReactProvider < T > ) : void {
742748 const index = ++ this . contextIndex ;
743- const context : ReactContext < any > = provider . type . _context ;
744- const previousValue = context . _currentValue ;
749+ // NOTE: in __DEV__ the _context and Consumer references are different,
750+ // while in production they are the same. For consistent Map keys, always
751+ // use context.Consumer.
752+ const context : ReactContext < any > = provider.type._context.Consumer;
753+ const previousValue = this.contextValueMap.has(context)
754+ ? this.contextValueMap.get(context)
755+ : context._currentValue;
745756
746757 // Remember which value to restore this context to on our way up.
747758 this.contextStack[index] = context;
@@ -752,7 +763,7 @@ class ReactDOMServerRenderer {
752763 }
753764
754765 // Mutate the current value.
755- context . _currentValue = provider . props . value ;
766+ this.contextValueMap.set(context, provider.props.value) ;
756767 }
757768
758769 popProvider < T > (provider: ReactProvider< T > ): void {
@@ -778,7 +789,7 @@ class ReactDOMServerRenderer {
778789 this . contextIndex -- ;
779790
780791 // Restore to the previous value we stored as we were walking down.
781- context . _currentValue = previousValue ;
792+ this . contextValueMap . set ( context , previousValue ) ;
782793 }
783794
784795 read ( bytes : number ) : string | null {
@@ -988,7 +999,9 @@ class ReactDOMServerRenderer {
988999 case REACT_CONTEXT_TYPE : {
9891000 const consumer : ReactConsumer < any > = ( nextChild : any ) ;
9901001 const nextProps : any = consumer . props ;
991- const nextValue = consumer . type . _currentValue ;
1002+ const nextValue = this . contextValueMap . has ( consumer . type )
1003+ ? this . contextValueMap . get ( consumer . type )
1004+ : consumer . type . _currentValue ;
9921005
9931006 const nextChildren = toArray ( nextProps . children ( nextValue ) ) ;
9941007 const frame : Frame = {
0 commit comments