@@ -231,7 +231,7 @@ def test_simple_input_with_use_state(driver, display):
231231 @idom .element
232232 async def Input (message = None ):
233233 message , set_message = idom .hooks .use_state (message )
234- message_ref .set ( message )
234+ message_ref .current = message
235235
236236 async def on_change (event ):
237237 if event ["value" ] == "this is a test" :
@@ -251,21 +251,143 @@ async def on_change(event):
251251 assert message_ref .current == "this is a test"
252252
253253
254- def test_use_effect_callback_occurs_after_full_layout_update_is_complete ():
255- # TODO: right now it runs after the element is rendered, not the full layout update
256- assert False
254+ async def test_use_effect_callback_occurs_after_full_render_is_complete ():
255+ effect_triggered = idom . Ref ( False )
256+ effect_triggers_after_final_render = idom . Ref ( None )
257257
258+ @idom .element
259+ async def OuterElement ():
260+ return idom .html .div (
261+ ElementWithEffect (),
262+ CheckNoEffectYet (),
263+ )
258264
259- def test_use_effect_cleanup_occurs_on_will_render ():
260- assert False
265+ @idom .element
266+ async def ElementWithEffect ():
267+ @idom .hooks .use_effect
268+ def effect ():
269+ effect_triggered .current = True
261270
271+ return idom .html .div ()
262272
263- def test_use_effect_cleanup_occurs_on_will_unmount ():
264- assert False
273+ @idom .element
274+ async def CheckNoEffectYet ():
275+ effect_triggers_after_final_render .current = not effect_triggered .current
276+ return idom .html .div ()
265277
278+ async with idom .Layout (OuterElement ()) as layout :
279+ await layout .render ()
266280
267- def test_use_effect_memoization ():
268- assert False
281+ assert effect_triggered .current
282+ assert effect_triggers_after_final_render .current is not None
283+ assert effect_triggers_after_final_render .current
284+
285+
286+ async def test_use_effect_cleanup_occurs_on_will_render ():
287+ element_hook = idom .Ref (None )
288+ cleanup_triggered = idom .Ref (False )
289+ cleanup_triggered_before_next_render = idom .Ref (False )
290+
291+ @idom .element
292+ async def ElementWithEffect ():
293+ element_hook .current = idom .hooks .current_hook ()
294+ if cleanup_triggered .current :
295+ cleanup_triggered_before_next_render .current = True
296+
297+ @idom .hooks .use_effect
298+ def effect ():
299+ def cleanup ():
300+ cleanup_triggered .current = True
301+
302+ return cleanup
303+
304+ return idom .html .div ()
305+
306+ async with idom .Layout (ElementWithEffect ()) as layout :
307+ await layout .render ()
308+
309+ assert not cleanup_triggered .current
310+
311+ element_hook .current .schedule_render ()
312+ await layout .render ()
313+
314+ assert cleanup_triggered .current
315+ assert cleanup_triggered_before_next_render .current
316+
317+
318+ async def test_use_effect_cleanup_occurs_on_will_unmount ():
319+ outer_element_hook = idom .Ref (None )
320+ cleanup_triggered = idom .Ref (False )
321+ cleanup_triggered_before_next_render = idom .Ref (False )
322+
323+ @idom .element
324+ async def OuterElement ():
325+ outer_element_hook .current = idom .hooks .current_hook ()
326+ if cleanup_triggered .current :
327+ cleanup_triggered_before_next_render .current = True
328+ return ElementWithEffect ()
329+
330+ @idom .element
331+ async def ElementWithEffect ():
332+ @idom .hooks .use_effect
333+ def effect ():
334+ def cleanup ():
335+ cleanup_triggered .current = True
336+
337+ return cleanup
338+
339+ return idom .html .div ()
340+
341+ async with idom .Layout (OuterElement ()) as layout :
342+ await layout .render ()
343+
344+ assert not cleanup_triggered .current
345+
346+ outer_element_hook .current .schedule_render ()
347+ await layout .render ()
348+
349+ assert cleanup_triggered .current
350+ assert cleanup_triggered_before_next_render .current
351+
352+
353+ async def test_use_effect_memoization ():
354+ element_hook = idom .Ref (None )
355+ set_state_callback = idom .Ref (None )
356+ effect_run_count = idom .Ref (0 )
357+
358+ first_value = 1
359+ second_value = 2
360+
361+ @idom .element
362+ async def ElementWithMemoizedEffect ():
363+ element_hook .current = idom .hooks .current_hook ()
364+ state , set_state_callback .current = idom .hooks .use_state (first_value )
365+
366+ @idom .hooks .use_effect (args = [state ])
367+ def effect ():
368+ effect_run_count .current += 1
369+
370+ return idom .html .div ()
371+
372+ async with idom .Layout (ElementWithMemoizedEffect ()) as layout :
373+ await layout .render ()
374+
375+ assert effect_run_count .current == 1
376+
377+ element_hook .current .schedule_render ()
378+ await layout .render ()
379+
380+ assert effect_run_count .current == 1
381+
382+ set_state_callback .current (second_value )
383+ await layout .render ()
384+
385+ assert effect_run_count .current == 2
386+
387+ element_hook .current .schedule_render ()
388+ await layout .render ()
389+
390+ assert effect_run_count .current == 2
269391
270392
271393def test_use_reducer ():
0 commit comments