22import  React ,  {  Component ,  type  Node  }  from  'react' ; 
33import  PropTypes  from  'prop-types' ; 
44import  gud  from  'gud' ; 
5+ import  warning  from  'fbjs/lib/warning' ; 
6+ import  MAX_SIGNED_31_BIT_INT  from  './maxSigned31BitInt' ; 
57
68type  RenderFn < T >  =  ( value : T )  =>  Node ; 
79
@@ -11,7 +13,8 @@ export type ProviderProps<T> = {
1113} ; 
1214
1315export  type  ConsumerProps < T >  =  { 
14-  children : RenderFn < T >  |  [ RenderFn < T > ] 
16+  children : RenderFn < T >  |  [ RenderFn < T > ] , 
17+  observedBits ?: number 
1518} ; 
1619
1720export  type  ConsumerState < T >  =  { 
@@ -41,9 +44,9 @@ function createEventEmitter(value) {
4144 return  value ; 
4245 } , 
4346
44-  set ( newValue )  { 
47+  set ( newValue ,   changedBits )  { 
4548 value  =  newValue ; 
46-  handlers . forEach ( handler  =>  handler ( value ) ) ; 
49+  handlers . forEach ( handler  =>  handler ( value ,   changedBits ) ) ; 
4750 } 
4851 } ; 
4952} 
@@ -52,7 +55,10 @@ function onlyChild(children): any {
5255 return  Array . isArray ( children )  ? children [ 0 ]  : children ; 
5356} 
5457
55- function  createReactContext < T > (defaultValue: T): Context< T >  { 
58+ function  createReactContext < T > (
59+  defaultValue: T,
60+  calculateChangedBits: ?(a: T, b: T) =>  number 
61+ ) : Context < T >  { 
5662 const  contextProp =  '__create-react-context-'  +  gud ( )  +  '__' ; 
5763
5864 class  Provider  extends  Component < ProviderProps < T >>  { 
@@ -70,7 +76,39 @@ function createReactContext<T>(defaultValue: T): Context<T> {
7076
7177 componentWillReceiveProps ( nextProps )  { 
7278 if  ( this . props . value  !==  nextProps . value )  { 
73-  this . emitter . set ( nextProps . value ) ; 
79+  const  oldProps  =  this . props ; 
80+  const  {  value : newValue  }  =  nextProps ; 
81+  let changedBits : number ; 
82+  const  oldValue  =  oldProps . value ; 
83+  // Use Object.is to compare the new context value to the old value. 
84+  // Inlined Object.is polyfill. 
85+  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 
86+  if  ( 
87+  ( oldValue  ===  newValue  && 
88+  ( oldValue  !==  0  ||  1  /  oldValue  ===  1  /  newValue ) )  || 
89+  ( oldValue  !==  oldValue  &&  newValue  !==  newValue )  // eslint-disable-line no-self-compare 
90+  )  { 
91+  // No change. 
92+  changedBits  =  0 ; 
93+  }  else  { 
94+  changedBits  = 
95+  typeof  calculateChangedBits  ===  'function' 
96+  ? calculateChangedBits ( oldValue ,  newValue ) 
97+  : MAX_SIGNED_31_BIT_INT ; 
98+  if  ( process . env . NODE_ENV  !==  'production' )  { 
99+  warning ( 
100+  ( changedBits  &  MAX_SIGNED_31_BIT_INT )  ===  changedBits , 
101+  'calculateChangedBits: Expected the return value to be a '  + 
102+  '31-bit integer. Instead received: %s' , 
103+  changedBits 
104+  ) ; 
105+  } 
106+  changedBits  |=  0 ; 
107+ 
108+  if  ( changedBits  !==  0 )  { 
109+  this . emitter . set ( nextProps . value ,  changedBits ) ; 
110+  } 
111+  } 
74112 } 
75113 } 
76114
@@ -84,14 +122,29 @@ function createReactContext<T>(defaultValue: T): Context<T> {
84122 [ contextProp ] : PropTypes . object 
85123 } ; 
86124
125+  observedBits : number ; 
126+ 
87127 state : ConsumerState < T >  =  { 
88128 value : this . getValue ( ) 
89129 } ; 
90130
131+  componentWillReceiveProps ( nextProps )  { 
132+  const  {  observedBits  } =  nextProps 
133+  this . observedBits  =  observedBits  ===  undefined  ||  observedBits  ===  null 
134+  // Subscribe to all changes by default 
135+  ? MAX_SIGNED_31_BIT_INT 
136+  : observedBits 
137+  } 
138+ 
91139 componentDidMount ( ) { 
92140 if  ( this . context [ contextProp ] )  { 
93141 this . context [ contextProp ] . on ( this . onUpdate ) ; 
94142 } 
143+  const  {  observedBits }  =  this . props 
144+  this . observedBits  =  observedBits  ===  undefined  ||  observedBits  ===  null 
145+  // Subscribe to all changes by default 
146+  ? MAX_SIGNED_31_BIT_INT 
147+  : observedBits 
95148 } 
96149
97150 componentWillUnmount ( ) { 
@@ -108,10 +161,11 @@ function createReactContext<T>(defaultValue: T): Context<T> {
108161 } 
109162 } 
110163
111-  onUpdate  =  ( )  =>  { 
112-  this . setState ( { 
113-  value : this . getValue ( ) 
114-  } ) ; 
164+  onUpdate  =  ( newValue ,  changedBits  : number )  =>  { 
165+  const  observedBits : number  =  this . observedBits  |  0 ; 
166+  if  ( ( observedBits  &  changedBits )  !==  0 )  { 
167+  this . setState ( {  value : this . getValue ( )  } ) 
168+  } 
115169 } ; 
116170
117171 render ( ) { 
0 commit comments