Extend rx.memo configuration and function memoization - #7084
Conversation
|
| transformed = hooks.compile_component( | ||
| memo.component, | ||
| page_context=page_context, | ||
| compile_context=compile_context, | ||
| ) |
There was a problem hiding this comment.
Recursive extraction loses parameter scope
A recursive memo returning rx.text(label + State.count.to(str)) contains a reactive expression that references its labelRxMemo parameter. This pass extracts that expression into an auto-memo definition, but generated wrappers accept only children and receive no captured parameters. The extracted component therefore references an unbound labelRxMemo and raises a ReferenceError during rendering. Forward the enclosing memo parameters into generated wrappers, or prevent extraction of expressions that depend on those locals.
| _DEFAULT_FUNCTION_MEMO_WRAPPER: FunctionVar = FunctionStringVar.create( | ||
| "(fn) => { const resultKey = Symbol(); const cache = new Map(); " | ||
| "return (...args) => { let node = cache; for (const arg of args) { " | ||
| "if (!node.has(arg)) node.set(arg, new Map()); node = node.get(arg); } " | ||
| "if (!node.has(resultKey)) node.set(resultKey, fn(...args)); " | ||
| "return node.get(resultKey); }; }" | ||
| ) |
There was a problem hiding this comment.
Packed arguments always miss cache
Function memos declaring children or rx.RestProp pack their arguments into a fresh JavaScript object literal. Repeated calls such as merge_styles(base=base, color="red") therefore use a different Map key on every render, even when the inputs are unchanged. The default cache never reuses the result and permanently retains every temporary props object and result. Key these signatures by their logical argument values rather than the fresh transport object, and add a repeated-call regression test.
| if name.isidentifier(): | ||
| return True | ||
| if not name or name[0] not in "_$": | ||
| return False | ||
| return all( | ||
| char in "_$" or "a" <= char <= "z" or "A" <= char <= "Z" or "0" <= char <= "9" | ||
| for char in name[1:] | ||
| ) |
There was a problem hiding this comment.
Valid dollar-sign names are rejected
A valid JavaScript name such as name="format$total" fails Python’s isidentifier() check, then fails this fallback because its first character is neither _ nor $. This unnecessarily prevents users from choosing names allowed by the documented JavaScript-identifier contract. Allow ASCII letters as initial characters in the fallback and test a name containing an interior $.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Merging this PR will not alter performance
Comparing Footnotes
|
Summary
by_value,recursive, and JavaScript-safenameoptions to@rx.memoTesting
uv run --no-sync pytest -q tests/units/components/test_memo.py tests/units/compiler/test_memoize_plugin.py(246 passed)Notes
by_valueusesJSON.stringify, including its cyclic-value and serialization limitations.Type of change
New Feature Submission
Changes To Core Features