@@ -154,27 +154,54 @@ Async Effects
154
154
.............
155
155
156
156
A behavior unique to ReactPy's implementation of ``use_effect `` is that it natively
157
- supports ``async `` functions:
157
+ supports ``async `` effects. Async effect functions may either be an async function
158
+ or an async generator. If your effect doesn't need to do any cleanup, then you can
159
+ simply write an async function.
158
160
159
161
.. code-block ::
160
162
161
163
async def non_blocking_effect():
162
- resource = await do_something_asynchronously()
163
- return lambda: blocking_close(resource)
164
+ await do_something()
164
165
165
166
use_effect(non_blocking_effect)
166
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.
167
171
168
- There are **three important subtleties ** to note about using asynchronous effects:
172
+ .. code-block ::
173
+
174
+ async def blocking_effect():
175
+ await do_something()
176
+ try:
177
+ yield False
178
+ finally:
179
+ await do_cleanup()
169
180
170
- 1. The cleanup function must be a normal synchronous function.
181
+ use_effect(blocking_effect)
171
182
172
- 2. Asynchronous effects which do not complete before the next effect is created
173
- following a re-render will be cancelled. This means an
174
- :class: `~asyncio.CancelledError ` will be raised somewhere in the body of the effect.
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.
186
+
187
+ .. code-block ::
188
+
189
+ async def establish_connection():
190
+ connection = await open_connection()
191
+ try:
192
+ while True:
193
+ yield False
194
+ await connection.send(create_message())
195
+ handle_message(await connection.recv())
196
+ finally:
197
+ await close_connection(connection)
198
+
199
+ use_effect(non_blocking_effect)
175
200
176
- 3. An asynchronous effect may occur any time after the update which added this effect
177
- and before the next effect following a subsequent update.
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.
178
205
179
206
180
207
Manual Effect Conditions
0 commit comments