T
TanStack2y ago
manual-pink

How to use additive context?

I have an app that moves linearly from screen to screen. I want to accumulate a little bit of data on each screen and submit a payload at the end comprised of the merged bits I fetched on each of the previous screens. This is my simplified route structure.
|-- routes
| |-- load-todo
| |-- index.tsx
| |-- show-todo
| |-- index.tsx
|-- routes
| |-- load-todo
| |-- index.tsx
| |-- show-todo
| |-- index.tsx
There are a few places in the docs that say something similar to this (emphasis mine)
🧠 Context is a powerful tool for dependency injection. You can use it to inject services, hooks, and other objects into your router and routes. _You can also additively pass data down the route tree at every route using a route's beforeLoad option._
🧠 Context is a powerful tool for dependency injection. You can use it to inject services, hooks, and other objects into your router and routes. _You can also additively pass data down the route tree at every route using a route's beforeLoad option._
Maybe I'm reading this wrong but it sounds like it's saying if I pass something into the beforeLoad callback in the load-todo/index.tsx createFileRoute call it should be available everywhere down the tree but I only see the type getting returned from beforeLoad merged to the context object within load-todo/index.tsx itself, not show-todo/index.tsx. If I'm making the wrong assumption about how this is meant to work then is there a better way to accumulate type-safe state as i traverse down the tree? My other idea is to accumulate the state in search params validating that accumulated state as I traverse using Zod's composition options. Here's a link to a Codesandbox demonstrating a simplified version of what I'm trying to do: https://codesandbox.io/p/github/trevorfehrman/tanstack-router-example/main?import=true Thanks in advance for any insight anyone might have, I've searched through the questions here and on GitHub but wasn't able to find an answer : /
10 Replies
stormy-gold
stormy-gold2y ago
So what's happening is, that the routes under show-todo are a child of load-todo, but not a child of load-todo's index. You could solve this, by having your actual beforeLoad logic being put into src/routes/load-todo.route.tsx, then all the show-todo routes will inherit this shared context. Additionally, when loading any of the routes, you can mutate that context into something else as well.
src/routes
load-todo/
index.tsx
route.tsx <- put it here
show-todo/
index.tsx
src/routes
load-todo/
index.tsx
route.tsx <- put it here
show-todo/
index.tsx
Your visualization of the routing tree was absolutely correct 👍🏼, just that load-todo's index and the show-todo routes were that of siblings, not parent-child.
manual-pink
manual-pinkOP2y ago
Interesting... I think I must have NextJS brain when trying to grok the file based routing here because the parent/child relationships here aren't clicking. Do I just need to read this page more carefully? https://tanstack.com/router/latest/docs/framework/react/guide/route-trees
Route Trees & Nesting | TanStack Router Docs
Like most other routers, TanStack Router uses a nested route tree to match up the URL with the correct component tree to render. To build a route tree, TanStack Router supports both:
stormy-gold
stormy-gold2y ago
File-Based Routes | TanStack Router Docs
Most of the TanStack Router documentation is written for file-based routing. This guide is mostly intended to help you understand in more detail how to configure file-based routing and the technical details behind how it works. Prerequisites
stormy-gold
stormy-gold2y ago
My explanation for it would be... in this structure,
src/routes/
posts/
index.tsx
$postId.tsx
route.tsx
src/routes/
posts/
index.tsx
$postId.tsx
route.tsx
The route.tsx in src/routes/posts using the route token is used for creating common configuration between all routes under the /posts route. If I share { foo: 'bar' } in the beforeLoad callback in this file, it'll then be available to both the index.tsx and $postId.tsx files. And this applies to all of its nested routes beneath it. It propagates, until it hits a beforeLoad that then overwrites the values being passed down.
manual-pink
manual-pinkOP2y ago
This is probably not the perfect metaphor but is it like the route.tsx file creates an enclosure around the sub-tree treating itself as the root, providing its context to anything below it, whereas the index.tsx can't have children per se even if there are routes that would match against a more specific URL i.e. posts/some-other-route/index.tsx? Just following up here because your advice worked perfectly and this is exactly the behavior I need. Thank you so much for your quick response. Codesandbox: https://codesandbox.io/p/github/trevorfehrman/tanstack-router-example/main?import=true The distinction between a route file and an index file is still a little elusive to me after reading the docs. Maybe this is a more widespread convention I'm not aware of in React-Router and/or Remix, I'll do some digging into other systems to see if I can fill in some of the gaps. Having said all that keep up the great work on this project! It's one of my favorites.
stormy-gold
stormy-gold2y ago
Yup, the route token can be considered to be the root of the /posts route, whilst the index token presents the actual index (/) at /posts/. TSR also has nested and flat, file-based routing (you can even mix em). Give it a shot, its certainly a break from the same-file-name syndrome folks from Next have to deal with.
src/routes/
index.tsx
(group-for-load-todo)/
load-todo.route.tsx
load-todo.index.tsx
load-todo.show-todo.index.tsx
src/routes/
index.tsx
(group-for-load-todo)/
load-todo.route.tsx
load-todo.index.tsx
load-todo.show-todo.index.tsx
It makes it great for looking up a file without having to go through the file-tree. Just Cmd + P, and type in the file you want.
manual-pink
manual-pinkOP2y ago
I strongly considered this convention for the app I'll be developing at work for which the code I linked here is a PoC for exactly the reasons you mention (1000000 index.tsx's) but the real app has many more screens and many branching paths. The current implementation of the app simply lists all the screens out in alphabetical order, making it a chore to try to remember which screen leads to which. Something I really like about the directory approach for my specific problem is the file tree becomes a visual representation of the possible ways for a user to traverse the app. I guess now that i think about it a little more, using the pattern you pasted above, especially given the ability to use those "invisible" folders i.e. (group-for-load-todo) I could keep the same visual representation of those traversals couldn't I
stormy-gold
stormy-gold2y ago
Yup, its finding what works for you. Like I said, you can mix it both flat and nested. So, you could even have.
src/routes
index.tsx
load-todo/
route.tsx
index.tsx
show-todo.index.tsx
src/routes
index.tsx
load-todo/
route.tsx
index.tsx
show-todo.index.tsx
manual-pink
manual-pinkOP2y ago
Yeah that's awesome, I'll take the temp of my team and figure out which one feels the best to them
stormy-gold
stormy-gold2y ago
🙌🏼

Did you find this page helpful?