Rendering order of routes seems backwards from normal react mental model
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Which project does this relate to?
Router
Describe the bug
Normal I'd expect react to render outside in, and then commit inside out. This is what normally happens with plain React, and just to be sure I double checked react-router v7 w streaming, and it seems to work as expected there too.
For example, in a route tree like this:
<Root>
<PostsRoute>
<PostRoute>
W a console.log in the render, and console.log in a useEffect at each level, react-router works as expected - renders outside in, and then commits inside out:
However, this same tree with tanstack-start ends up looking like the below. It's an outside in pattern, but combining the render and commit phases at each level:
So I guess first a question - is this the intended behavior? If it is the intended behavior, maybe worth calling out somewhere? Or maybe I'm just out of the loop and I should know these things 😅. That said, not sure how to work around the different rendering model for the global state example described below, and just in general this might cause subtle issues in the broader ecosystem?
A concrete example of how this can cause issues (and this was not trivial to debug and get to the bottom of...):
- A typical pattern is to initialize global stores in a
Providerswrapper component, in the root route - The providers might instantiate various libs, that internally
useEffectin order to initialize their state after the react tree has been hydrated - A child route/component in the tree accesses this global state in order to render some part of the UI
- If by the time the child is rendering for the first time (thus, not hydrated yet), the global state has already been updated (even though this state was supposed to be updated after hydration is finished), causing things like hydration mismatch errors can occur
At least that's what I THINK is going on, I could be totally wrong 😅.
The example over at https://github.com/marbemac/tanstack-start-render-order-bug showcases the issue, where rendering works as expected in react router, but not in tanstack start.
Tanstack start:
React router:
Does the expected rendering/committing, in the expected order, and then one more render at the end that represents the useEffect that is updating that global state, and causing the post route to re-render (no hydration mismatch, since it has already finished hydrating).
Your Example Website or App
https://github.com/marbemac/tanstack-start-render-order-bug
Steps to Reproduce the Bug or Issue
See instructions in the linked repo.
Expected behavior
As a react user, I expect react to render outside in, and then commit inside out.
Screenshots or Videos
No response
Platform
- OS: [e.g. macOS, Windows, Linux]
- Browser: [e.g. Chrome, Safari, Firefox]
- Version: [e.g. 91.1]
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproduction repository linked in the issue and follow its instructions. Compare the root Providers wrapper and nested route tree in TanStack Start with the React Router version, tracing render, useEffect, and hydration order. Done means the observed behavior is explained and either corrected or clearly documented as intended, including the global-state example.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100