@@ -2138,6 +2138,66 @@ describe('ReactHooksWithNoopRenderer', () => {
2138
2138
expect ( ReactNoop ) . toMatchRenderedOutput ( '2' ) ;
2139
2139
} ) ;
2140
2140
2141
+ // Regression test. Covers a case where an internal state variable
2142
+ // (`didReceiveUpdate`) is not reset properly.
2143
+ it ( 'state bail out edge case (#16359)' , async ( ) => {
2144
+ let setCounterA ;
2145
+ let setCounterB ;
2146
+
2147
+ function CounterA ( ) {
2148
+ const [ counter , setCounter ] = useState ( 0 ) ;
2149
+ setCounterA = setCounter ;
2150
+ Scheduler . unstable_yieldValue ( 'Render A: ' + counter ) ;
2151
+ useEffect ( ( ) => {
2152
+ Scheduler . unstable_yieldValue ( 'Commit A: ' + counter ) ;
2153
+ } ) ;
2154
+ return counter ;
2155
+ }
2156
+
2157
+ function CounterB ( ) {
2158
+ const [ counter , setCounter ] = useState ( 0 ) ;
2159
+ setCounterB = setCounter ;
2160
+ Scheduler . unstable_yieldValue ( 'Render B: ' + counter ) ;
2161
+ useEffect ( ( ) => {
2162
+ Scheduler . unstable_yieldValue ( 'Commit B: ' + counter ) ;
2163
+ } ) ;
2164
+ return counter ;
2165
+ }
2166
+
2167
+ const root = ReactNoop . createRoot ( null ) ;
2168
+ await ReactNoop . act ( async ( ) => {
2169
+ root . render (
2170
+ < >
2171
+ < CounterA />
2172
+ < CounterB />
2173
+ </ > ,
2174
+ ) ;
2175
+ } ) ;
2176
+ expect ( Scheduler ) . toHaveYielded ( [
2177
+ 'Render A: 0' ,
2178
+ 'Render B: 0' ,
2179
+ 'Commit A: 0' ,
2180
+ 'Commit B: 0' ,
2181
+ ] ) ;
2182
+
2183
+ await ReactNoop . act ( async ( ) => {
2184
+ setCounterA ( 1 ) ;
2185
+
2186
+ // In the same batch, update B twice. To trigger the condition we're
2187
+ // testing, the first update is necessary to bypass the early
2188
+ // bailout optimization.
2189
+ setCounterB ( 1 ) ;
2190
+ setCounterB ( 0 ) ;
2191
+ } ) ;
2192
+ expect ( Scheduler ) . toHaveYielded ( [
2193
+ 'Render A: 1' ,
2194
+ 'Render B: 0' ,
2195
+ 'Commit A: 1' ,
2196
+ // B should not fire an effect because the update bailed out
2197
+ // 'Commit B: 0',
2198
+ ] ) ;
2199
+ } ) ;
2200
+
2141
2201
it ( 'should update latest rendered reducer when a preceding state receives a render phase update' , ( ) => {
2142
2202
// Similar to previous test, except using a preceding render phase update
2143
2203
// instead of new props.
0 commit comments