R

ReflexKR

Reflex Docs

Reflex Basics, Hands-On

·

Course overview

1

Click and it changes: State and events

2

Now you see it: conditional rendering

3

Drawing lists: rx.foreach

4

Why doesn't if work? Compile time vs. runtime

5

Making it look good: components, props and style

6

Apps, pages and a fruit basket

Reflex Basics, Hands-On
Lesson 4

Time 0:18–0:28

Why doesn't if work? Compile time vs. runtime

In Lesson 2 you used rx.cond instead of if, and in Lesson 3 you used rx.foreach instead of for. It's Python, so why can't you just use regular Python syntax? Once you understand the answer, most of the errors you'll run into in Reflex suddenly make sense.

4-1. Two moments when code runs (3 min)

The code in a Reflex app runs at two different moments.

Compile timeRuntime
WhenOnce, when the app startsContinuously, while the app is running
WhatUI functions (show_login, render_item …)Event handlers (increment, toggle_login …)
WherePython code is turned into JavaScript (React) codePython on the server
State valuesNot known yetThe real values are there

When the app starts, UI functions are translated into JavaScript and sent to the browser. At translation time, nobody knows which user will click what yet, so LoginState.logged_in inside a UI function isn't a real True/False. It's a placeholder that "gets filled in later, in the browser." That placeholder is exactly what a Var is.

Event handlers, on the other hand, aren't translated. They run as plain Python on the server, so inside a handler you can use any Python code or library you like.

4-2. Inside a handler, it's real Python (2 min)

The handler below uses if and even calls a function defined outside the State. It runs on the server at runtime, so that's no problem.

def check_even(num: int):
    return num % 2 == 0


class MyState3(rx.State):
    count: int = 0
    text: str = "even"

    @rx.event
    def increment(self):
        # Use any Python code within state.
        # Even reference functions defined outside the state.
        if check_even(self.count):
            self.text = "even"
        else:
            self.text = "odd"
        self.count += 1


def count_and_check():
    return rx.box(
        rx.heading(MyState3.text, as_="h2"),
        rx.button("Increment", on_click=MyState3.increment),
    )

localhost:3000

Try it

even

On every click, a Python if inside the handler picks even or odd.

You can use Python inside UI functions too, but only on values already known at compile time (anything that doesn't use a state var). Below, range(5) and check_even(i) are fully evaluated when the app starts.

def show_numbers():
    return rx.vstack(*[rx.text(f"{i} is {'even' if check_even(i) else 'odd'}") for i in range(5)])

localhost:3000

Live preview

0 is even

1 is odd

2 is even

3 is odd

4 is even

Five lines computed at compile time. These values never change while the app is running.

4-3. Three things that don't work in UI code (2 min)

Because state var values aren't known at compile time, each of the following raises an error inside a UI function.

Checking a Var's value with if: whether it's true or false isn't known yet. The same goes for choosing a prop value.

class BadState(rx.State):
    count: int = 0


def count_if_even():
    return rx.box(
        rx.heading("Count: ", as_="h2"),
        # This will raise a compile error, as BadState.count is a var and not known at compile time.
        rx.text(BadState.count if BadState.count % 2 == 0 else "Odd"),
        # Using an if statement with a var as a prop will NOT work either.
        rx.text("hello", color="red" if BadState.count % 2 == 0 else "blue"),
    )

Looping over a list Var with for: how many items it holds isn't known yet.

class BadState(rx.State):
    items: list[str] = ["Apple", "Banana", "Cherry"]


def loop_over_list():
    return rx.box(
        # This will raise a compile error, as BadState.items is a list and not known at compile time.
        *[rx.text(item) for item in BadState.items]
    )

Passing a Var to a Python function like len(): there's no string to count characters in yet.

class BadTextState(rx.State):
    text: str = "Hello world"


def format_text():
    return rx.box(
        # Python operations such as `len` will not work on state vars.
        rx.text(len(BadTextState.text)),
    )

4-4. The fix: Var operations (3 min)

So how do you show "Even if it's even, Odd if it's odd" on the page? Reflex provides Var operations that work on Vars. When you use operators like %, == or > on a Var, the result is also a Var, and the actual calculation happens in the browser once the value arrives.

class CountEvenState(rx.State):
    count: int = 0

    @rx.event
    def increment(self):
        self.count += 1


def count_if_even():
    return rx.box(
        rx.heading("Count: ", CountEvenState.count, as_="h2"),
        rx.cond(
            # Here we use the `%` and `==` var operations to check if the count is even.
            CountEvenState.count % 2 == 0,
            rx.text("Even"),
            rx.text("Odd"),
        ),
        rx.button("Increment", on_click=CountEvenState.increment),
    )

localhost:3000

Try it

Count: 0

Even

rx.cond takes the result of the % and == Var operations and picks Even or Odd.

Now one table sums up why you needed the tools from Lessons 1 to 3.

What you wantDoesn't work in UI codeUse this instead
Different content depending on a conditionif / elserx.cond(condition, if_true, if_false)
Looping over a listfor, list comprehensionsrx.foreach(items, render_fn)
Getting a lengthlen(x)x.length()
Math and comparisonsPassing Vars to Python functionsVar operations like %, ==, >
Complex calculationsPython inside a UI functionCompute in an event handler and store it in State

Good to know — When in doubt, ask yourself: "When does this code run?" Inside a UI function, it's compile time, so a Var is still an empty placeholder. Inside a handler, it's runtime, so you have the real value.

Exercises

  1. Fix format_text from 4-3 so it shows the number of characters. Hint: BadTextState.text.length().
  2. In count_if_even, show "Big!" when count is 10 or more. Hint: rx.cond(CountEvenState.count >= 10, ...).
  3. Compare computing inside the handler, as in MyState3, with using Var operations, as in CountEvenState. Which one needs fewer State variables?

Checkpoint

  • You can say when and where UI functions and event handlers each run.
  • You can explain why you can't use if, for or len() on state vars in UI code.
  • You know how to do the same things with Var operations, rx.cond and rx.foreach.

← Previous

Lesson 3 · Drawing lists: rx.foreach

Next →

Lesson 5 · Making it look good: components, props and style

Get news about new lessons

We'll email you when this course gets new lessons or a follow-up course opens.

We collect: your email address · Purpose: news about new lessons or the launch of this course · Kept until: you ask us to remove it. We never use it for anything else or share it. Reply to any notice email and we'll delete it right away.

Questions & answers

Ask anything about this lesson. Questions from every language version of this page appear together.

Shown as plain text, without links or formatting.

R

ReflexKR

Learn Python and Reflex by doing. Every example was run and verified on Reflex 0.10.0.

ReflexKR is free, with no banner ads. If it helped you, you can support it with a coffee. ☕ Buy us a coffee

Affiliate disclosure
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex