Skip to content

fix: render hooks in declaration order instead of by HookPosition - #7586

Merged
masenf merged 3 commits into
reflex-dev:mainfrom
FarhanAliRaza:farhan/hook-declaration-order
Oct 20, 2026
Merged

masenf merged 3 commits into
reflex-dev:mainfrom
FarhanAliRaza:farhan/hook-declaration-order

Conversation

@FarhanAliRaza

@FarhanAliRaza FarhanAliRaza commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Closes #7584.

Problem

VarData keeps hooks in an ordered tuple, and it merges each hook's dependencies before the hook. _sort_hooks then split the hooks into INTERNAL, PRE_TRIGGER and POST_TRIGGER buckets, which broke that order. Two parts of the code lose a hook's position:

  • VarData.merge cannot keep two different positions.
  • _get_added_hooks writes code[sub_hook] = None, which overwrites the INTERNAL position that the component's own prop hooks gave the same hook.

So a hook can render before a declaration it reads. This happens on main with one component: a prop with a derived hook, plus an add_hooks Var that reads the same state:

const derived = s.a_rx_state_ + 1        // INTERNAL
const s = useStateContext("...")         // overwritten to PRE_TRIGGER
const added = s.a_rx_state_

Fix

  • _render_hooks joins the hooks in the order they were declared and merged. _sort_hooks and the unused memo slot are removed.
  • VarData no longer has a position field. VarData(position=...) still works, but it shows a deprecation warning and has no effect. Hooks.HookPosition stays, and its docstring marks it as deprecated.
  • The framework's own position uses are removed: the ref, mount, var and event-loop hooks, window_event_listener and clipboard.

Tests

  • test_hooks_render_after_the_state_hook_they_read: the case above. It fails on main.
  • test_hooks_render_after_their_dependencies: random hook graphs (25 seeds), read through props and through add_hooks across a random component tree. Each hook must render after the hooks it reads. 11 of the 25 seeds fail on main.
  • test_var_data_position_is_deprecated_and_ignored: the argument warns, and hooks with different positions now merge in order instead of raising.

Validation outside the unit tests

I compiled each app on main and on this branch, ran ESLint no-use-before-define on every generated module, and compared each component's hook sequence:

App Modules use-before-define (main / branch) Components with a changed hook order
examples/playground 58 0 / 0 1 of 335
a fixture with every hook-adding component 22 0 / 0 2 of 18
a small shop app 24 0 / 0 0 of 52
reflex-enterprise dnd + mantine demos 26 0 / 0 0 of 21

The three reorders do not change behaviour: the state declaration still comes before every reader, and a useEffect moves before some useRef declarations. The same ESLint check finds the error in #7583's head that was reported there, so the check can detect this bug.

Prod builds of playground (20 routes) and the fixture load with no page or console errors. On the fixture, window_event_listener (resize), clipboard (paste) and form submit work.

The enterprise dnd and combobox code passes position= and now gets the deprecation warning. Its compiled output does not change.

Follow-ups

View guided diff

Hooks are kept in an ordered tuple inside VarData, and every hook's
dependencies are merged before it. The INTERNAL / PRE_TRIGGER /
POST_TRIGGER buckets reordered that sequence. VarData.merge also could
not keep two positions, and _get_added_hooks overwrote a hook's position
with None, so a hook could render before a state declaration it reads.

_render_hooks now joins the hooks in the order they were declared and
merged. VarData drops the position field; the position argument is
deprecated and ignored. The framework's own position uses (ref, mount,
var and event-loop hooks, window_event_listener, clipboard) are removed.

Closes reflex-dev#7584
@FarhanAliRaza
FarhanAliRaza requested a review from a team as a code owner October 16, 2026 19:40
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T19:47:08.724226Z 4b44632 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 13 files

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

@greptile-apps

greptile-apps Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The PR appears safe to merge; the latest documentation matches the current hook collection code.

Summary

The PR renders hooks in declaration order and deprecates VarData(position=...).

  • Hooks render in the order they are declared and merged.
  • VarData(position=...) no longer changes hook order.

Reviews (3) · Last reviewed commit: "docs: describe declaration-order hooks i..." · Reviewed by Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b4463216f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@codspeed

codspeed Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ 14 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 145 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ test_state_access[write_own] 126.1 ms 132.3 ms -4.69%
⚡ test_compile_all_artifacts[_repeated_stateful_page] 467.7 ms 446.4 ms +4.79%
⚡ test_compile_page[_repeated_stateful_page] 543.8 ms 522.2 ms +4.15%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing FarhanAliRaza:farhan/hook-declaration-order (fdce21f) with main (5ae5dcd)

Open in CodSpeed

Document that a hook reading state must be a Var that carries it.

@masenf masenf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good after fixing outstanding reviewbot comments

The guide told wrapper authors to set VarData.position, which is now
deprecated and ignored. Document declaration order and VarData(hooks=...)
for a hook that reads another hook's declaration instead, and mark the
components-core fragment as a bugfix with its user-visible result.

Claude-Session: https://claude.ai/code/session_01SyBSxfLKyRDRQrKJqcg3Wh
@FarhanAliRaza
FarhanAliRaza requested a review from Alek99 as a code owner October 16, 2026 20:46
@masenf masenf added bug Something isn't working documentation Improvements or additions to documentation breaking Public API facing change considered for minor release bump pre-v1.0 labels Oct 19, 2026 — with ChatGPT Codex Connector
@masenf masenf added the on deck PRs lined up to review / merge next label Oct 19, 2026

@masenf masenf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reflex-components-core already depends on in-tree version of reflex-base, so no bump was required.

@masenf
masenf merged commit d3f4ab1 into reflex-dev:main Oct 20, 2026
154 of 156 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Public API facing change considered for minor release bump pre-v1.0 bug Something isn't working documentation Improvements or additions to documentation on deck PRs lined up to review / merge next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Get rid of HookPosition

2 participants