Skip to content

Commit b66d987

Browse files
committed
update docs
1 parent e5655d0 commit b66d987

File tree

1 file changed

+41
-31
lines changed

1 file changed

+41
-31
lines changed

Diff for: docs/source/reference/hooks-api.rst

+41-31
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ Use Effect
8989

9090
.. code-block::
9191
92-
use_effect(did_render)
92+
@use_effect
93+
def did_render():
94+
... # imperative or state mutating logic
9395
9496
The ``use_effect`` hook accepts a function which may be imperative, or mutate state. The
9597
function will be called immediately after the layout has fully updated.
@@ -117,12 +119,11 @@ then closing a connection:
117119

118120
.. code-block::
119121
122+
@use_effect
120123
def establish_connection():
121124
connection = open_connection()
122125
return lambda: close_connection(connection)
123126
124-
use_effect(establish_connection)
125-
126127
The clean-up function will be run before the component is unmounted or, before the next
127128
effect is triggered when the component re-renders. You can
128129
:ref:`conditionally fire events <Conditional Effects>` to avoid triggering them each
@@ -141,14 +142,19 @@ example, imagine that we had an effect that connected to a ``url`` state variabl
141142
142143
url, set_url = use_state("https://example.com")
143144
145+
@use_effect
144146
def establish_connection():
145147
connection = open_connection(url)
146148
return lambda: close_connection(connection)
147149
148-
use_effect(establish_connection)
149-
150150
Here, a new connection will be established whenever a new ``url`` is set.
151151

152+
.. warning::
153+
154+
A component will be unable to render until all its outstanding effects have been
155+
cleaned up. As such, it's best to keep cleanup logic as simple as possible and/or
156+
to impose a time limit.
157+
152158

153159
Async Effects
154160
.............
@@ -160,48 +166,52 @@ simply write an async function.
160166

161167
.. code-block::
162168
163-
async def non_blocking_effect():
169+
@use_effect
170+
async def my_async_effect():
164171
await do_something()
165172
166-
use_effect(non_blocking_effect)
167-
168-
However, if you need to do any cleanup, then you must ``yield False`` inside a try-finally
169-
block and place your cleanup logic in the finally block. Yielding ``False`` indicates to
170-
ReactPy that the effect will not yield again before it is cleaned up.
173+
However, if you need to do any cleanup, then you'll need to write an async generator
174+
instead. The generator should run the effect logic in a ``try`` block, ``yield`` control
175+
back to ReactPy, and then run the cleanup logic in a ``finally`` block:
171176

172177
.. code-block::
173178
174-
async def blocking_effect():
175-
await do_something()
179+
@use_effect
180+
async def my_async_effect():
176181
try:
177-
yield False
182+
await effect_logic()
183+
yield
178184
finally:
179-
await do_cleanup()
180-
181-
use_effect(blocking_effect)
185+
await cleanup_logic()
182186
183-
If you have a long-lived effect, you may ``yield True`` multiple times. ``True`` indicates
184-
to ReactPy that the effect will yield again if the effect doesn't need to be cleanup up
185-
yet.
187+
When a component is re-rendered or unmounted the effect will be cancelled if it is still
188+
running. This will typically happen for long-lived effects. One example might be an
189+
effect that opens a connection and then responds to messages for the lifetime of the
190+
connection:
186191

187192
.. code-block::
188193
189-
async def establish_connection():
190-
connection = await open_connection()
194+
@use_effect
195+
async def my_async_effect():
196+
conn = await open_connection()
191197
try:
192198
while True:
193-
yield False
194-
await connection.send(create_message())
195-
handle_message(await connection.recv())
199+
msg = await conn.recv()
200+
await handle_message(msg)
196201
finally:
197-
await close_connection(connection)
202+
await close_connection(conn)
203+
204+
.. warning::
205+
206+
Because an effect can be cancelled at any time, it's possible that the cleanup logic
207+
will run before all of the effect logic has finished. For example, in the code
208+
above, we exclude ``conn = await open_connection()`` from the ``try`` block because
209+
if the effect is cancelled before the connection is opened, then we don't need to
210+
close it.
198211

199-
use_effect(non_blocking_effect)
212+
.. note::
200213

201-
Note that, if an effect needs to be cleaned up, it will only do so when the effect
202-
function yields control back to ReactPy. So you should ensure that either, you can
203-
be sure that the effect will yield in a timely manner, or that you enforce a timeout
204-
on the effect. Otherwise, ReactPy may hang while waiting for the effect to yield.
214+
We don't need a yield statement here because the effect only ends when it's cancelled.
205215

206216

207217
Manual Effect Conditions

0 commit comments

Comments
 (0)