1212let React ;
1313let ReactDOM ;
1414
15- describe ( 'ReactDOMSuspensePlaceholder ' , ( ) => {
15+ describe ( 'ReactDOMHooks ' , ( ) => {
1616 let container ;
1717
1818 beforeEach ( ( ) => {
@@ -29,6 +29,83 @@ describe('ReactDOMSuspensePlaceholder', () => {
2929 document . body . removeChild ( container ) ;
3030 } ) ;
3131
32+ it ( 'can ReactDOM.render() from useEffect' , ( ) => {
33+ let container2 = document . createElement ( 'div' ) ;
34+ let container3 = document . createElement ( 'div' ) ;
35+
36+ function Example1 ( { n} ) {
37+ React . useEffect ( ( ) => {
38+ ReactDOM . render ( < Example2 n = { n } /> , container2 ) ;
39+ } ) ;
40+ return 1 * n ;
41+ }
42+
43+ function Example2 ( { n} ) {
44+ React . useEffect ( ( ) => {
45+ ReactDOM . render ( < Example3 n = { n } /> , container3 ) ;
46+ } ) ;
47+ return 2 * n ;
48+ }
49+
50+ function Example3 ( { n} ) {
51+ return 3 * n ;
52+ }
53+
54+ ReactDOM . render ( < Example1 n = { 1 } /> , container ) ;
55+ expect ( container . textContent ) . toBe ( '1' ) ;
56+ expect ( container2 . textContent ) . toBe ( '' ) ;
57+ expect ( container3 . textContent ) . toBe ( '' ) ;
58+ jest . runAllTimers ( ) ;
59+ expect ( container . textContent ) . toBe ( '1' ) ;
60+ expect ( container2 . textContent ) . toBe ( '2' ) ;
61+ expect ( container3 . textContent ) . toBe ( '3' ) ;
62+
63+ ReactDOM . render ( < Example1 n = { 2 } /> , container ) ;
64+ expect ( container . textContent ) . toBe ( '2' ) ;
65+ expect ( container2 . textContent ) . toBe ( '2' ) ; // Not flushed yet
66+ expect ( container3 . textContent ) . toBe ( '3' ) ; // Not flushed yet
67+ jest . runAllTimers ( ) ;
68+ expect ( container . textContent ) . toBe ( '2' ) ;
69+ expect ( container2 . textContent ) . toBe ( '4' ) ;
70+ expect ( container3 . textContent ) . toBe ( '6' ) ;
71+ } ) ;
72+
73+ it ( 'can batch synchronous work inside effects with other work' , ( ) => {
74+ let otherContainer = document . createElement ( 'div' ) ;
75+
76+ let calledA = false ;
77+ function A ( ) {
78+ calledA = true ;
79+ return 'A' ;
80+ }
81+
82+ let calledB = false ;
83+ function B ( ) {
84+ calledB = true ;
85+ return 'B' ;
86+ }
87+
88+ let _set ;
89+ function Foo ( ) {
90+ _set = React . useState ( 0 ) [ 1 ] ;
91+ React . useEffect ( ( ) => {
92+ ReactDOM . render ( < A /> , otherContainer ) ;
93+ } ) ;
94+ return null ;
95+ }
96+
97+ ReactDOM . render ( < Foo /> , container ) ;
98+ ReactDOM . unstable_batchedUpdates ( ( ) => {
99+ _set ( 0 ) ; // Forces the effect to be flushed
100+ expect ( otherContainer . textContent ) . toBe ( '' ) ;
101+ ReactDOM . render ( < B /> , otherContainer ) ;
102+ expect ( otherContainer . textContent ) . toBe ( '' ) ;
103+ } ) ;
104+ expect ( otherContainer . textContent ) . toBe ( 'B' ) ;
105+ expect ( calledA ) . toBe ( false ) ; // It was in a batch
106+ expect ( calledB ) . toBe ( true ) ;
107+ } ) ;
108+
32109 it ( 'should not bail out when an update is scheduled from within an event handler' , ( ) => {
33110 const { createRef, useCallback, useState} = React ;
34111
0 commit comments