Skip to content

Releases: reflex-dev/reflex

v0.7.14

03 Jun 02:09
Compare
Choose a tag to compare

Release Notes

[WARNING: different UI output] add style recursive for memo

Previously, we were not adding the app styles to memoized components. Now that's fixed, but in certain apps some of your memoized components might look different, so adjust your styles after upgrading.

Context on what page failed to evaluate

If you're on Python 3.11+, you will get a helpful message indicating which route is the one that caused the error.

Full Logging support

If you want to run reflex with a high loglevel but want to store debug logs just in case. You can set the environment variable REFLEX_ENABLE_FULL_LOGGING to true. This will by default store it in the user directory (something like .locals/shared/reflex). You can change the path of the log file with the environment variable REFLEX_LOG_FILE.

Components Improvements

Bugfixes

Chores

Misc

Full Changelog: v0.7.13...release/reflex-0.7.14

v0.7.13

26 May 19:03
Compare
Choose a tag to compare

Release Notes

Remove Pydantic as a base class of Component

rx.Component used to inherit from BaseModel, but that's no longer the case. We opted to write our own Metaclass to handle the specific needs of Components better.

This has great improvements for hot reload time for small apps as Pydantic spent around 75% of import time just deep copying fields. On my own machine, a hot reload of a simple app went down from ~1.2sec to just around 200ms!

While this is not intended to be a breaking change, it's likely that a very introspective code could behave differently with this one. So please test it and report to us so we can preserve behavior as best as possible.

length() for dicts

If you are using object vars (State fields of type dict or Base/dataclasses), you can now call .length() on them. This is a simple wrapper over .keys().length().

Allow Vars to be the result of the render function of Foreach

This relaxes the requirement from being a component. Vars are wrapped in a Fragment.

Prefix Config Vars with REFLEX_

The environment variables defined in Config will now be read with REFLEX_ as a prefix. Previous not prefixed names are still names but are deprecated.

Stronger type checking against partially filled variables

If you were unlucky enough, you might have written some code where you capture some arguments but reflex decides that it wants to give your event handler even more arguments. In these cases, we weren't checking the types of such arguments against the event callback. This now triggers a compilation error.

Ignore certain file formats from hot reload

Granian was reloading on more file formats than necessary, so we manually exclude a set of file formats that are unlikely to be a cause of hot reload. If you still notice weird hot reloads on file changes that are irrelevant to your application, we can append that list with more values.

Tailwind V3 is now contained in a module (and rudimentary Reflex Plugin System)

We now have a basic plugins system with a few hooks. It's not very documented, but you can basically provide a list of plugins to the plugins argument in rx.Config. You can add compile time hooks to create files, modify files, define stylesheets, define javascript dependencies, and more.

We moved our tailwind v3 code to use such plugin system. You should either set tailwind=None inside of your rx.Config or set plugins to [rx.plugins.TailwindV3Plugin()]. Automatic assumption of tailwind is deprecated.

We're also starting our work on Tailwind V4. You can try it by setting plugnis to rx.plugins.TailwindV4Plugin().

Bugfixes

Chores

Full Changelog: v0.7.12...v0.7.13

v0.7.12

19 May 21:10
c27bd39
Compare
Choose a tag to compare

Release Notes

Bugfixes

Chores

Full Changelog: v0.7.11...v0.7.12

v0.7.11

12 May 21:11
9b8aab9
Compare
Choose a tag to compare

Release Notes

[DEPRECATION] rx.next.video

It wasn't particularly usable to begin with.

Slightly stronger hydration mismatch strictness

This will stop you from putting rx.el.p inside of a rx.el.p and such.

Add option to disable auto-setters

This can allow you to be more explicit on what public State fields can be set by the user.

Use Javascript syntax over JSX

This shouldn't affect you, but our output code is now using normal Javascript and no JSX syntax. This solves some of the issues we had with context swapping between Vars and Components.

Upgrade rx.icon

Lucide has updated their list of icons, and now those changes are available in Reflex.

Remove Cond as a Memoization leaf

This might improve the runtime performance of your frontend!

  • Allow auto memoization of Component Cond by @masenf in #5272

Optimizations

  • ⚑️ Speed up function to_camel_case by 128% by @misrasaurabh1 in #5239
  • use knowledge about generic types to improve their getters and checkers by @adhami3310 in #5245
  • optimize rx.color to not use validate literal parameters by @adhami3310 in #5244

Bugfixes

Misc

Chores

New Contributors

Full Changelog: v0.7.10...v0.7.11

v0.7.10

05 May 18:48
Compare
Choose a tag to compare

Release Notes

Decentralized Event Handlers

You can define some events outside of the state they belong to. This requires using the @event decorator and typing the first (state) argument with the state it belongs to. It gets used by its name as opposed to State. format.

import reflex as rx

class State(rx.State):
    field: int = 23

@rx.event
def update_field(state: State, new_value: int):
    state.field = new_value

def index() -> rx.Component:
    return rx.vstack(
        State.field,
        rx.button(
            "Update Field",
            on_click=update_field(321),
        ),
    )

app = rx.App()
app.add_page(index)

Escape hatch: change react version

In case react version upgrade broke your packages somehow, you can use the REACT_VERSION environment flag to change it. We don't support this flag indefinitely though, and it's very much not safe to set.

Decimal support in Vars

You can now use decimal in state, but it converts it to a float when sending it to JS. Devin has contributed some of this PR before needing to intervene a bit.

Style for dragging over upload component

on_drop for Upload should now support the list syntax. Also adds a style to the default component when a file is being dragged over it.

  • Upload: drag_active_style and multiple on_drop specs by @masenf in #5207

[Regression Fix] Lifespan tasks

If you were using lifespan tasks along api or api_transformer, it might not have been running as expected. It should be fixed now.

This also fixes hot reload on Windows.

Bugfixes

Chores

New Contributors

Full Changelog: v0.7.9...v0.7.10

v0.7.9

29 Apr 00:26
Compare
Choose a tag to compare

Release Notes

Improvements to Tailwind Config Wrapping

Thanks to @itsmeadarsh2008, the tailwind config got expanded:

plugins = [
    "@tailwindcss/forms",  # simple require
    {
        "name": "@heroui/theme",
        "import": {"name": "heroui", "from": "@heroui/theme"},
        "call": "heroui"
    },
    {
        "name": "tailwindcss-theme-variants",
        "import": {"name": "themeVariants", "from": "tailwindcss-theme-variants"},
        "call": "themeVariants",
        "args": {
            "themes": {
                "light": { "selector": ".light-theme" },
                "dark": { "selector": ".dark-theme" }
            }
        }
    }
]

Enable Granian as default

We have had fixes going into Granian that should make the experience as good as it was on Uvicorn/Gunicorn and in some cases better. There are most certainly issues so feel free to report them and we will do our best to mitigate them.

Include all rx.memo components in the build

This saves us from doing another scan to discover them.

This also adds the ability to call memoized components from dynamic components!

class State(rx.State):
    name: str = "Bob"

    @rx.var
    def count(self) -> rx.Component:
        return counter(
            name=self.name,
        )


@rx.memo
def counter(name: str):
    return rx.hstack(
        rx.button(name),
        rx.button(f"Not {name}"),
    )


def index():
    return rx.vstack(rx.text("Who Are You?"), State.count)

Deprecate .api in favor of api_transformer

If you were doing something like:

app = rx.App()

@app.api.get("/pong")
def pong():
    return {"message": "pong"}

You should instead do

fastapi_app = FastAPI()

@fastapi_app.get("/pong")
def pong():
    return {"message": "pong"}

app = rx.App(api_transformer=fastapi_app)

The api_transformer takes one or multiple (a list) of Starlette/FastAPI apps. It can also take a function that takes ASGIApp and returns a different ASGIApp that mounts the previous one. For example, the above code is equivalent to:

from reflex.utils.types import ASGIApp

fastapi_app = FastAPI()

@fastapi_app.get("/pong")
def pong():
    return {"message": "pong"}

def fastapi_transformer(app: ASGIApp):
    fastapi_app.mount("", app)
    return app

app = rx.App(api_transformer=fastapi_transformer)

Raise error when using @rx.event with events starting with an underscore.

Private events is not a thing and this can help to error earlier.

Replace typer with click

In our quest to cut down on dependencies we are simplifying our CI across reflex and reflex-hosting-cli to use click over typer (which what typer uses under the hood).

Misc

Bugfixes

Chores

New Contributors

Full Changelog: v0.7.8...v0.7.9

v0.7.8

21 Apr 19:10
Compare
Choose a tag to compare

Release Notes

is_none() and is_not_none() operations.

If you were getting some of those pesky lint errors because you were doing some_var == None, you can do some_var.is_none() instead.

Call event handlers with keyword arguments

Although pyright will be mad at you.

import reflex as rx


class State(rx.State):
    """The app state."""

    field: int = 0

    @rx.event
    def change_field(self, new_value: int):
        """Change the state field."""
        self.field = new_value


def index() -> rx.Component:
    return rx.button(
        "Click me!",
        State.field,
        on_click=State.change_field(new_value=2),
    )


app = rx.App()
app.add_page(index)

NextJS upgrade (15.3.0)

This includes faster builds if you enable the environment variable REFLEX_USE_TURBOPACK.

Bugfixes

Chores

Full Changelog: v0.7.7...v0.7.8

v0.7.7

15 Apr 02:45
f821ce3
Compare
Choose a tag to compare

Release Notes

el.input with type=range and type=number correctly reports events of type (float) -> Any

Sames goes for el.input with type=checkbox and event type (bool) -> Any.

This can be a subtle breaking change if you had code depending on this small detail.

rx.el.input(
    type="checkbox"
    on_change=rx.console_log # prints false and true now
)
  • allow int and float typing for input elements behind a warning by @adhami3310 in #5098

Bun version behavior fixes

Reflex will use system host if either:

  1. You passed REFLEX_USE_SYSTEM_BUN. It will warn you if your version of bun is outdated, but will ultimately let you run reflex.
  2. You don't have a reflex-installed bun and you do have bun installed on your system and it's up to date.

Otherwise, Reflex uses or downloads/installs or updates its local version of bun that is shared between your reflex applications.

  • be less whiny about bun version and suggest alternatives by @adhami3310 in #5106

Hosting CLI Improvements

Reflex hosting cli will now support uploading a local sqlite db as long as it is less than 25mb. This will give the hosted site an ephemeral database. Meaning that new data added could be lost but data uploaded is always persisted.

To achieve this a user must leverage the cloud config (reflex cloud config) with the following flag include_db: True

Bugfixes

Chores

Full Changelog: v0.7.6...v0.7.7

v0.7.6

08 Apr 23:36
Compare
Choose a tag to compare

Release Notes

Admin dashboard is optional now

Admin dashboard (that is, starlette_admin), is now not included by default. If you want to retain it, just install the starlette-admin package.

Removing custom components publish command

To lower the number of dependencies and making the framework less opinionated about what tools to use, we're removing the reflex components publish. Our recommendation is to use reflex components build followed by twine upload or uv publish, or really any package upload utility.

Add value and default_value to rx.el.select

I don't know why it wasn't there originally.

  • Add value and default_value to rx.el.select by @masenf in #5079

Add context to add_page

Thanks to @hjpr, now you can provide context as a parameter for pages to be used by middlewares if you're building Reflex plugins.

  • Added param context to add_page for extended functionality for plugins, flows, etc. by @hjpr in #5091

Bugfixes

Chores

Full Changelog: v0.7.5...v0.7.6

v0.7.5

31 Mar 19:39
Compare
Choose a tag to compare

Release Notes

NextJS back at latest version

As we have had more bugs related to the downgrade, we now have upgraded it back and disable turbopack by default. You can overwrite nextjs version with NEXTJS_VERSION but it is very much NOT SUPPORTED. Expect bugs when you do so.

Event handlers as Vars

Not flashy, but you can use handlers in conds and such

on_click=rx.cond(
  SnakeState.game_over,
  SnakeState.start_game,
  SnakeState.pause_game
)

This only works when the event handler takes no arguments, however, you should use the much more reliable:

on_click=rx.cond(
  SnakeState.game_over,
  SnakeState.start_game(),
  SnakeState.pause_game()
)

Where you call the event handlers. You can use lambda syntax to provide arguments for them.

Expose Socket constants for further customizability

Exposes REFLEX_SOCKET_MAX_HTTP_BUFFER_SIZE, REFLEX_SOCKET_INTERVAL, REFLEX_SOCKET_TIMEOUT to be modified.

Add support for ndigits for dunder method round for int vars

round(State.int_field, 3)

Expose run_in_thread

rx.run_in_thread is a simple wrapper around asyncio to run a function in a different thread.

Allow None as children of components

Previously we errored, but now we allow it, it doesn't render to anything.

Allow arguments for rx.memo event handlers

@rx.memo
def counter(on_text: rx.EventHandler[rx.event.passthrough_event_spec(str)]):
    return rx.hstack(
        rx.button("Increment", on_click=on_text("Increment")),
        rx.button("Decrement", on_click=on_text("Decrement")),
    )


def index():
    return rx.vstack(rx.text("Counter"), counter(on_text=rx.console_log))

You can even define your own event spec

def hello_who(who: rx.Var[str]) -> tuple[rx.Var[str]]:
    return (rx.Var.create(f"Hello, {who}!"),)


@rx.memo
def counter(on_text: rx.EventHandler[hello_who]):
    return rx.hstack(
        rx.button("Masen", on_click=on_text("Masen")),
        rx.button("Not Masen", on_click=on_text("Not Masen")),
    )


def index():
    return rx.vstack(rx.text("Who Are You?"), counter(on_text=rx.console_log))
  • allow arguments to be passed to rx memo event handlers by @adhami3310 in #5021

Bugfixes

Chores

Full Changelog: v0.7.4...v0.7.5