@@ -19,6 +19,7 @@ describe('useRef', () => {
19
19
let act ;
20
20
let useCallback ;
21
21
let useEffect ;
22
+ let useLayoutEffect ;
22
23
let useRef ;
23
24
let useState ;
24
25
@@ -33,6 +34,7 @@ describe('useRef', () => {
33
34
act = ReactNoop . act ;
34
35
useCallback = React . useCallback ;
35
36
useEffect = React . useEffect ;
37
+ useLayoutEffect = React . useLayoutEffect ;
36
38
useRef = React . useRef ;
37
39
useState = React . useState ;
38
40
} ) ;
@@ -124,4 +126,108 @@ describe('useRef', () => {
124
126
ReactNoop . render ( < Counter /> ) ;
125
127
expect ( Scheduler ) . toFlushAndYield ( [ 'val' ] ) ;
126
128
} ) ;
129
+
130
+ if ( __DEV__ ) {
131
+ it ( 'should not warn about reads if value is not mutated' , ( ) => {
132
+ function Example ( ) {
133
+ const ref = useRef ( 123 ) ;
134
+ return ref . current ;
135
+ }
136
+
137
+ act ( ( ) => {
138
+ ReactNoop . render ( < Example /> ) ;
139
+ } ) ;
140
+ } ) ;
141
+
142
+ it ( 'should warn about reads during render phase if value has been mutated' , ( ) => {
143
+ function Example ( ) {
144
+ const ref = useRef ( 123 ) ;
145
+ ref . current = 456 ;
146
+
147
+ let value ;
148
+ expect ( ( ) => {
149
+ value = ref . current ;
150
+ } ) . toWarnDev ( [ 'useRef: Unsafe read of a mutable ref during render.' ] ) ;
151
+
152
+ return value ;
153
+ }
154
+
155
+ act ( ( ) => {
156
+ ReactNoop . render ( < Example /> ) ;
157
+ } ) ;
158
+ } ) ;
159
+
160
+ it ( 'should not warn about lazy init pattern' , ( ) => {
161
+ function Example ( ) {
162
+ const ref = useRef ( null ) ;
163
+ if ( ref . current === null ) {
164
+ // Read 1: safe because null
165
+ ref . current = 123 ;
166
+ }
167
+ return ref . current ; // Read 2: safe because lazy init
168
+ }
169
+
170
+ act ( ( ) => {
171
+ ReactNoop . render ( < Example /> ) ;
172
+ } ) ;
173
+ } ) ;
174
+
175
+ it ( 'should warn about updates to ref after lazy init pattern' , ( ) => {
176
+ function Example ( ) {
177
+ const ref = useRef ( null ) ;
178
+ if ( ref . current === null ) {
179
+ // Read 1: safe because null
180
+ ref . current = 123 ;
181
+ }
182
+ expect ( ref . current ) . toBe ( 123 ) ; // Read 2: safe because lazy init
183
+
184
+ ref . current = 456 ; // Second mutation, now reads will be unsafe
185
+
186
+ expect ( ( ) => {
187
+ expect ( ref . current ) . toBe ( 456 ) ; // Read 3: unsafe because mutation
188
+ } ) . toWarnDev ( [ 'useRef: Unsafe read of a mutable ref during render.' ] ) ;
189
+
190
+ return null ;
191
+ }
192
+
193
+ act ( ( ) => {
194
+ ReactNoop . render ( < Example /> ) ;
195
+ } ) ;
196
+ } ) ;
197
+
198
+ it ( 'should not warn about reads witin effect' , ( ) => {
199
+ function Example ( ) {
200
+ const ref = useRef ( 123 ) ;
201
+ ref . current = 456 ;
202
+ useLayoutEffect ( ( ) => {
203
+ expect ( ref . current ) . toBe ( 456 ) ;
204
+ } , [ ] ) ;
205
+ useEffect ( ( ) => {
206
+ expect ( ref . current ) . toBe ( 456 ) ;
207
+ } , [ ] ) ;
208
+ return null ;
209
+ }
210
+
211
+ act ( ( ) => {
212
+ ReactNoop . render ( < Example /> ) ;
213
+ } ) ;
214
+
215
+ ReactNoop . flushPassiveEffects ( ) ;
216
+ } ) ;
217
+
218
+ it ( 'should not warn about reads outside of render phase (e.g. event handler)' , ( ) => {
219
+ let ref ;
220
+ function Example ( ) {
221
+ ref = useRef ( 123 ) ;
222
+ ref . current = 456 ;
223
+ return null ;
224
+ }
225
+
226
+ act ( ( ) => {
227
+ ReactNoop . render ( < Example /> ) ;
228
+ } ) ;
229
+
230
+ expect ( ref . current ) . toBe ( 456 ) ;
231
+ } ) ;
232
+ }
127
233
} ) ;
0 commit comments