TanStack / TanStack/router

Rendering order of routes seems backwards from normal react mental model

Open
#3,478 3 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

information needed
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:

Image

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:

Image

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 Providers wrapper component, in the root route
  • The providers might instantiate various libs, that internally useEffect in 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:

Image

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).

Image
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.