R

ReflexKR

Reflex公式ドキュメント

コンポーネント工房:Reflexライブラリ100

·

講座の概要

レイアウト

·

Box

·

Flex

·

Stack

·

Grid

·

Container

·

Section

·

Center

·

Spacer

·

Separator

·

Card

·

Inset

·

Aspect Ratio

·

Fragment

タイポグラフィ

·

Text

·

Heading

·

Link

·

Code

·

Markdown

·

Blockquote

·

Quote

·

Strong

·

Em

·

Kbd

フォーム

·

Button

·

Input

·

Text Area

·

Checkbox

·

Switch

·

Radio Group

·

Select

·

Slider

·

Form

·

Upload

データ表示

·

Badge

·

Avatar

·

Icon

·

Callout

·

List

·

Data List

·

Code Block

·

Progress

·

Spinner

·

Scroll Area

·

Moment

開閉と切り替え

·

Tabs

·

Accordion

·

Segmented Control

オーバーレイ

·

Tooltip

·

Popover

·

Hover Card

·

Dialog

·

Alert Dialog

·

Drawer

·

Dropdown Menu

·

Context Menu

·

Toast

動的レンダリング

·

Cond

·

Match

·

Foreach

·

Auto Scroll

メディア

·

Image

·

Audio

·

Video

表とデータグリッド

·

Table

·

Data Table

·

Data Editor

チャート

·

Area Chart

·

Bar Chart

·

Line Chart

·

Composed Chart

·

Pie Chart

·

Radar Chart

·

Radial Bar Chart

·

Scatter Chart

·

Funnel Chart

·

Treemap

·

Sankey Chart

·

Error Bar

チャートの部品

·

Axis

·

Cartesian Grid

·

Chart Tooltip

·

Legend

·

Label

·

Reference

·

Brush

ほかのチャートライブラリ

·

Plotly

·

Pyplot

HTML要素

·

HTML

·

HTML Text

·

HTML Layout

·

HTML Forms

·

HTML Media

·

HTML Tables

·

SVG

そのほかの道具

·

Theme

·

Skeleton

·

Clipboard

·

Html Embed

·

Script

·

Memo

コンポーネント工房:Reflexライブラリ100
そのほかの道具

Memo

rx.memorx.RestProprx.EMPTY_VAR_STR

公式ドキュメント

工房の注文書

カートの数が変わるたびに隣の商品カードの一覧まで再描画されないよう、カードだけを切り出してください。

@rx.memoは関数をメモ化された React コンポーネントに変えます。コンパイラーはその関数を独立したモジュールとして書き出し、React のmemoが、宣言されたプロパティが変わったときだけ再描画します。 描画が重く、State のごく一部にしか依存しないサブツリーに使います。このページの@rx.memo関数は、すべて例のコードの上側(State のソース)で定義されています。

Count: 0

Memoized Component

This component only re-renders when props change.

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

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


@rx.memo
def memo_expensive_component(label: rx.Var[str]) -> rx.Component:
    return rx.vstack(
        rx.heading(label, as_="h2", size="4"),
        rx.text("This component only re-renders when props change."),
        rx.divider(),
    )


rx.vstack(
    rx.text("Count: ", MemoDemoState.count),
    rx.button("Increment", on_click=MemoDemoState.increment),
    memo_expensive_component(label="Memoized Component"),
)

memo_expensive_componentはlabelが変わったときだけ再描画されます。Incrementでcountを増やしても、このコンポーネントは再描画されません。

State の値をプロパティに

rx.memoには目に見えるプロパティがないので、実習台の代わりに State で動く例で見ていきます。プロパティには State の Var をそのまま渡せ、その Var が変わると再描画されます。

Hello, World

class MemoGreetState(rx.State):
    name: str = "World"

    @rx.event
    def change_name(self, value: str):
        self.name = value


@rx.memo
def memo_greeting(name: rx.Var[str]) -> rx.Component:
    return rx.heading("Hello, " + name, as_="h2", size="5")


rx.vstack(
    memo_greeting(name=MemoGreetState.name),
    rx.input(value=MemoGreetState.name, on_change=MemoGreetState.change_name),
)

呼び出す側で State をプロパティに結び付けても、State がページに引き込まれることはありません。コンパイラーがその呼び出しを自動生成のラッパーコンポーネントに移し、ラッパーが必要な State のフックを持ちます。 State が変わるとラッパーは再描画されますが、プロパティの値が実際には変わっていなければ、React のmemoがそこで止めます。重いコンポーネントには本当に必要な Var だけを渡すのがコツです。

ルール

型注釈値既定値用途
rx.Var[T]str, int, TypedDict …なし普通のプロパティ。関数の中では Var として扱う
rx.RestPropパラメーター1つまでなし宣言していない残りのプロパティをそのまま渡す(JSX の...rest)
children: rx.Var[rx.Component]名前は必ずchildrenなし呼び出す側の子コンポーネント
既定値rx.EMPTY_VAR_STR rx.EMPTY_VAR_INT rx.EMPTY_VAR_COMPONENTなし既定値も Var でなければならない。空文字列・0・空のコンポーネント
呼び出しmemo_fn(title="...")プロパティは名前(キーワード)でだけ渡す
wrapper=Var またはNoneReact のmemo包む JavaScript の関数

rx.foreach と一緒に

リストの項目ごとにメモコンポーネントを描くには、呼び出しをラムダで包み、プロパティをキーワードで渡します。項目を区別するkeyも一緒に渡します。 keyが実際の要素に届くよう、rx.RestPropのパラメーターを宣言して、返すコンポーネントに展開して入れます。keyをシグネチャーに直接宣言してはいけません。 関数の中のtaskは dict ではなく Var なので、task["name"]のように取り出して使うことはできますが、ループしたり.keys()のような dict のメソッドを呼んだりはできません。

Write docs

Review PR

from typing import TypedDict


class MemoTask(TypedDict):
    id: str
    name: str


class MemoTaskState(rx.State):
    tasks: list[MemoTask] = [
        {"id": "1", "name": "Write docs"},
        {"id": "2", "name": "Review PR"},
    ]

    @rx.event
    def add_task(self):
        n = len(self.tasks) + 1
        self.tasks = [*self.tasks, {"id": str(n), "name": f"Task {n}"}][-6:]


@rx.memo
def memo_task_card(rest: rx.RestProp, *, task: rx.Var[MemoTask]) -> rx.Component:
    return rx.card(rx.text(task["name"]), rest)


rx.vstack(
    rx.foreach(
        MemoTaskState.tasks,
        lambda task: memo_task_card(task=task, key=task["id"]),
    ),
    rx.button("Add task", on_click=MemoTaskState.add_task, variant="soft"),
)

rx.RestProp でプロパティを渡す

rx.RestPropは宣言していないプロパティを受け取って、そのまま渡します。基本のコンポーネントに見た目だけを付けた薄いラッパーを作るとき、プロパティをひとつずつ宣言し直さずに済みます。 restは中身をのぞけない値として扱い、使うコンポーネントに位置引数として渡します。on_click、id、titleがすべてrestに乗ってボタンに届きます。

@rx.memo
def memo_pill_button(rest: rx.RestProp, *, label: rx.Var[str]) -> rx.Component:
    return rx.button(label, rest, radius="full", variant="surface")


rx.flex(
    memo_pill_button(label="Save", on_click=rx.toast("Saved"), id="memo_save"),
    memo_pill_button(label="Help", on_click=rx.toast("Help is on the way"), title="Opens help"),
    spacing="3",
)

.mergeでrestに別の dict を合わせることができ、rest.get(...)で値を取り出して Var の演算ができます。ただし値はコンパイル時にはわからないので、Python のifで分岐することはできません。 Reflex 0.10 で公式ドキュメントの例をそのまま使うと、2か所が食い違います。restはブラウザで使う JavaScript の名前(className)を持っているので"class_name"では取り出せず、 rest.get(...)の結果は型が決まっていない Var なので、そのまま+ " ..."をするとエラーになります。そこで"className"で取り出して合わせ、.to(str)で文字列の Var に変えてから足します。

@rx.memo
def memo_merged_button(rest: rx.RestProp, *, label: rx.Var[str]) -> rx.Component:
    class_name = rest.get("className", "").to(str) + " font-bold tracking-wide"
    return rx.button(label, rest.merge({"className": class_name}))


rx.flex(
    memo_merged_button(label="Default"),
    memo_merged_button(label="Caller class", class_name="italic"),
    spacing="3",
)

限界:ビルド時に使われるプロパティ

rx.RestPropはプロパティを実行時に渡すので、対象コンポーネントのcreate()がビルド時に使う値は運べません。 rx.linkのis_external、rx.iconのtag、自作のcreate()が受け取るキーワードがそうです。restで送ると、ただの属性や CSS になって何の効果もありません。 こうした値は別にrx.Var[...]のパラメーターとして受け取り、関数の本体でcreate()に直接渡します。

P: Foo
class MemoPrefixText(rx.el.Span):
    @classmethod
    def create(cls, *children, prefix: rx.Var[str] | str = "", **props) -> rx.Component:
        return super().create(prefix, *children, **props)


# prefix is used by create(), so it is not passed through rest.
# take it as its own parameter and pass it to create() in the memo body.
@rx.memo
def memo_styled_text(rest: rx.RestProp, *, prefix: rx.Var[str]) -> rx.Component:
    return MemoPrefixText.create("Foo", rest, prefix=prefix)


memo_styled_text(prefix="P: ", class_name="italic")

子要素を受け取る

名前がchildrenでrx.Var[rx.Component]と注釈したパラメーターが、呼び出す側の子要素を受け取ります。子要素は位置引数で、残りのプロパティはキーワードで渡します。 noteのように既定値がrx.EMPTY_VAR_STRのプロパティは省略できます。

Memoized card

Body copy goes here.

With a note

note is optional

@rx.memo
def memo_panel(
    children: rx.Var[rx.Component],
    *,
    title: rx.Var[str],
    note: rx.Var[str] = rx.EMPTY_VAR_STR,
) -> rx.Component:
    return rx.box(
        rx.heading(title, as_="h3", size="3"),
        children,
        rx.text(note, size="1", color_scheme="gray"),
        padding="12px",
        border=f"1px solid {rx.color('gray', 6)}",
        border_radius="8px",
    )


rx.flex(
    memo_panel(rx.text("Body copy goes here."), title="Memoized card"),
    memo_panel(rx.button("Inside", size="1"), title="With a note", note="note is optional"),
    spacing="3",
    wrap="wrap",
)

コンポーネントの代わりに Var を返す

戻り値の注釈をrx.Var[T]にすると、コンポーネントではなく普通の JavaScript の関数が作られ、呼び出した場所はページに差し込んで使える Var になります。 このようなメモの本体はコンパイル時に一度だけ実行されるので、使えるのは Var の演算だけです。フックも、Var を見て行う Python の分岐もできません。

USD: $100

class MemoPriceState(rx.State):
    amount: int = 100
    currency: str = "USD"

    @rx.event
    def raise_price(self):
        self.amount += 10


@rx.memo
def memo_format_price(amount: rx.Var[int], currency: rx.Var[str]) -> rx.Var[str]:
    return currency.to(str) + ": $" + amount.to(str)


rx.hstack(
    rx.text(memo_format_price(amount=MemoPriceState.amount, currency=MemoPriceState.currency), weight="bold"),
    rx.button("+10", on_click=MemoPriceState.raise_price, size="1", variant="soft"),
    align="center",
)

JavaScript のラッパーを変える

コンパイルされた関数コンポーネントは、既定で React のmemoに包まれます。wrapper=に別の呼び出し可能な Var を渡せばそれで包み、wrapper=Noneなら包まない関数コンポーネントをそのまま書き出します。 下はwrapper=Noneの例です。コンポーネントを返すメモにだけ使え、Var を返すメモに渡すと拒否されます。

@rx.memo(wrapper=None)
def memo_swatch(width: rx.Var[int], height: rx.Var[int]) -> rx.Component:
    return rx.box(width=width.to_string() + "px", height=height.to_string() + "px", background=rx.color("indigo", 9), border_radius="4px")


rx.flex(
    memo_swatch(width=40, height=20),
    memo_swatch(width=80, height=20),
    memo_swatch(width=120, height=20),
    spacing="2",
    align="center",
)

ほかのライブラリの関数で包むときは、FunctionStringVarに import を載せて送ります。下の例はmobx-react-liteパッケージが必要なので、コードとしてだけ示します。

observer = rx.vars.FunctionStringVar(
    "observer",
    _var_data=rx.vars.VarData(imports={"mobx-react-lite": "observer"}),
)


@rx.memo(wrapper=observer)          # wrap with mobx's observer instead of React's memo
def observed_panel(label: rx.Var[str]) -> rx.Component:
    return rx.text(label)

いつ使い、いつ使わないか

使うとき:描画が重く、結果が少数のプロパティで決まり、頻繁に変わる祖先のせいで無駄に再描画されるとき。 使わないとき:軽いコンポーネントで、管理のコストのほうが高くつくとき。あるいはプロパティがどのみち毎回変わり、memoが一度もスキップできないとき。

古い rx.memo からの移行

以前のrx.memoはtitle: strのような普通の型注釈を受け取っていました。いまはrx.Var[...]が必要です。古い名前のrx._x.memoは新しいrx.memoにつながり、一度だけ案内のメッセージを出します。

# before
@rx.memo
def card(title: str) -> rx.Component: ...


# now
@rx.memo
def card(title: rx.Var[str]) -> rx.Component: ...

API

引数型用途
component_fnCallable[..., rx.Component | rx.Var]メモにする関数。パラメーターはすべてrx.Var[...]またはrx.RestProp
wrapperrx.Var | None包む JS の関数。既定は React のmemo、Noneなら包まない。コンポーネントを返すメモ専用

rx.memo(fn)のように直接使うか、rx.memo(wrapper=...)(fn)のようにキーワードだけを渡してデコレーターを作ります。

注文書を仕上げる

商品カードを@rx.memoで切り出しました。カードはproductだけを受け取るので、Add oneでカートの数が変わってもカードは再描画されません。 width="100%"はrestに乗ってカードに届きます。

0

Desk lamp

$39

Notebook

$6

Fountain pen

$58
from typing import TypedDict


class MemoProduct(TypedDict):
    id: str
    name: str
    price: str


class MemoShopState(rx.State):
    cart: int = 0
    products: list[MemoProduct] = [
        {"id": "p1", "name": "Desk lamp", "price": "$39"},
        {"id": "p2", "name": "Notebook", "price": "$6"},
        {"id": "p3", "name": "Fountain pen", "price": "$58"},
    ]

    @rx.event
    def add_one(self):
        self.cart += 1

    @rx.event
    def empty_cart(self):
        self.cart = 0


@rx.memo
def memo_product_card(rest: rx.RestProp, *, product: rx.Var[MemoProduct]) -> rx.Component:
    return rx.card(
        rx.flex(
            rx.icon("package", size=18),
            rx.text(product["name"], weight="bold"),
            rx.spacer(),
            rx.badge(product["price"], variant="soft"),
            spacing="3",
            align="center",
        ),
        rest,
    )


rx.vstack(
    rx.hstack(
        rx.badge(rx.icon("shopping-cart", size=14), MemoShopState.cart, size="2"),
        rx.button("Add one", on_click=MemoShopState.add_one, size="1"),
        rx.button("Empty", on_click=MemoShopState.empty_cart, size="1", variant="soft", color_scheme="gray"),
        align="center",
    ),
    rx.foreach(
        MemoShopState.products,
        lambda p: memo_product_card(product=p, key=p["id"], width="100%"),
    ),
    width="100%",
    max_width="380px",
)

工房ノート

  • @rx.memo は、宣言したプロパティが変わったときだけ再描画する React コンポーネントを作る。

  • パラメーターはすべて rx.Var[T] または rx.RestProp(1つまで)。子要素は children: rx.Var[rx.Component]。

  • 呼び出しはキーワードで。既定値は rx.EMPTY_VAR_STR のような Var。foreach では key を rest で。

  • rest は実行時に渡すプロパティだけ。create() がビルド時に使う値は別のパラメーターで。

  • -> rx.Var[T] なら JS の関数になる。wrapper=None は memo で包まない。

← 前へ

そのほかの道具 · Script

新しい授業・講座のお知らせを受け取る

この講座に授業が追加されたり、続きの講座が公開されたりしたらメールでお知らせします。

収集項目:メールアドレス・目的:この講座の新しい授業・公開のお知らせ・保有期間:解除のご依頼まで。他の目的には使わず、第三者にも提供しません。お知らせメールに返信いただければすぐに削除します。

質問と回答

この回について気になることを書き込んでください。すべての言語のページの質問がここに集まります。

リンクや書式なしで、そのままの文字で表示されます。

R

ReflexKR

触って学ぶPythonとReflex。すべての例はReflex 0.10.0で実際に動かして確認しています。

ReflexKRはバナー広告なし・無料で運営しています。役に立ったら、コーヒー一杯で応援してください。 ☕ コーヒーで応援する

アフィリエイトと支援について
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex