Skip to content

v0.2.8

Compare
Choose a tag to compare
@masenf masenf released this 22 Sep 17:57
· 1889 commits to main since this release
83d7a04

✨ This release is made possible in part by users like YOU! ✨

Breaking Changes

CopyToClipboard component has been removed.

Use the rx.set_clipboard special event instead.

New Features

get_event_triggers API

The new Component.get_event_triggers API combines the old get_triggers and get_controlled_triggers methods into a unified API (the previous methods will continue to work in 0.2.8, but wrapped components should move to the new API).

The new API is more flexible, providing control over handler and trigger argument mapping. The method is expected to return a dictionary of callables. The keys are the names of the triggers in the react component. The values are callables whose signature defines the javascript trigger signature and the return value is a list of args that will be passed to the python EventHandler function.

This allows wrapping of components that accept non-standard event handler functions. Typically a lambda is used to map arguments, but a regular function with type annotations can also be used to enable extended Var operations like indexing.

For example, the FormSelect component uses a non-standard signature for on_change, this can now be accomodated in the new API.

class FormSelect(rx.Component):
    library = "@patternfly/react-core"
    tag = "FormSelect"

    def get_event_triggers(self) -> Dict[str, Any]:
        return {
            EventTriggers.ON_CHANGE: lambda _e, value: [value],
        }

rx.download special event

The new download event prompts the frontend browser for file download.

It can be used directly as an event trigger:

rx.button("Download file", on_click=rx.download("/uri/for/file.extension", "target_file.extension")

Or it can be yielded from a backend event handler:

def export_data(self):
    ...
    # do export logic here and write to filepath
    # then
    yield rx.download(filepath, filename)

Register Serializers for Custom Types

A one-arg callable in a Reflex app or component module with @rx.serializer decorator will be considered a serializer for the type of its argument. This allows arbitrary types used on the backend to be accessed on the frontend, as long as there is a serializer defined that returns a JSON serializable value.

For example, the following code is used to serialize plotly Figure objects.

import json
from plotly.graph_objects import Figure
from plotly.io import to_json

@rx.serializer
def serialize_figure(figure: Figure) -> list:
    return json.loads(str(to_json(figure)))["data"]

Background Task Event Handlers that do not block other Events

An async EventHandler function in a State that is decorated with @rx.background is considered a "Background Task". When triggered by the frontend or chained from another event handler, it will spawn a long running task that will NOT block other EventHandlers from running.

There are three main differences from a normal EventHandler to be aware of:

  • Background Task must be async
  • Background Task cannot directly modify state values and state values may be stale if other events have modified the state since the task started running.
    • Only read or write state vars inside an async with self context block, where exclusive access to the latest state is guaranteed.
  • Background Task cannot be directly called from another event handler.
    • Must yield or return the background task to chain it from another handler.
class State(rx.State):

    counter: int = 0

    @rx.background
    async def bg_task(self):
        for ix in range(10):
            async with self:
                # state mutation is only allowed inside context block
                self.counter += 1

            # await long operations outside the context to avoid blocking
            await asyncio.sleep(0.5)

Full documentation for this feature is still being developed. Please post comments regarding background tasks on the discussion thread.

  • rx.background and StateManager.modify_state provides safe exclusive access to state by @masenf in #1676

Improvements

Support Reactivity for rx.Base fields

Modifying fields on an rx.Base instance will trigger updates in the state without having to reassign them. This also applies when working with fields that are container types such as list and dict.

  • Reassign state Var when fields on a Base instance change by @masenf in #1748

Better Error Messages

Usability

Bug Fixes

  • added check to remove local import starting from . by @wassafshahzad in #1807
  • exec: print the URL, not the address the server binds to by @masenf in #1846

Minor Changes and Fixups

New Contributors

Full Changelog: v0.2.7...v0.2.8