@@ -47,189 +47,32 @@ Basename path for the application.
4747
4848### opts .dataStrategy
4949
50- Override the default data strategy of running loaders in parallel .
51- See [` DataStrategyFunction ` ](https :// api.reactrouter.com/v7/interfaces/react_router.DataStrategyFunction.html).
52-
53- <docs-warning >This is a low-level API intended for advanced use-cases. This
54- overrides React Router's internal handling of
55- [`action`](../../start/data/route-object#action)/[`loader`](../../start/data/route-object#loader)
56- execution, and if done incorrectly will break your app code. Please use
57- with caution and perform the appropriate testing.</docs-warning >
58-
59- By default , React Router is opinionated about how your data is loaded / submitted -
60- and most notably , executes all of your [` loader ` ](../ ../ start / data / route - object #loader )s
61- in parallel for optimal data fetching . While we think this is the right
62- behavior for most use - cases , we realize that there is no " one size fits all"
63- solution when it comes to data fetching for the wide landscape of
64- application requirements .
65-
66- The ` dataStrategy ` option gives you full control over how your [` action ` ](../ ../ start / data / route - object #action )s
67- and [` loader ` ](../ ../ start / data / route - object #loader )s are executed and lays
68- the foundation to build in more advanced APIs such as middleware , context ,
69- and caching layers . Over time , we expect that we ' ll leverage this API
70- internally to bring more first class APIs to React Router , but until then
71- (and beyond ), this is your way to add more advanced functionality for your
72- application 's data needs .
73-
74- The `dataStrategy ` function should return a key /value -object of
75- `routeId ` -> [`DataStrategyResult `](https :// api.reactrouter.com/v7/interfaces/react_router.DataStrategyResult.html) and should include entries for any
76- routes where a handler was executed . A `DataStrategyResult ` indicates if
77- the handler was successful or not based on the `DataStrategyResult .type `
78- field . If the returned `DataStrategyResult .result ` is a [`Response `](https :// developer.mozilla.org/en-US/docs/Web/API/Response),
79- React Router will unwrap it for you (via [`res .json `](https :// developer.mozilla.org/en-US/docs/Web/API/Response/json)
80- or [`res .text `](https :// developer.mozilla.org/en-US/docs/Web/API/Response/text)).
81- If you need to do custom decoding of a [`Response `](https :// developer.mozilla.org/en-US/docs/Web/API/Response)
82- but want to preserve the status code , you can use the `data ` utility to
83- return your decoded data along with a `ResponseInit `.
84-
85- <details >
86- <summary ><b >Example <code >dataStrategy </code > Use Cases </b ></summary >
87-
88- **Adding logging **
89-
90- In the simplest case , let 's look at hooking into this API to add some logging
91- for when our route [`action `](../../start /data /route -object #action )s /[`loader `](../../start /data /route -object #loader )s
92- execute :
50+ Override the default data strategy of running loaders in parallel -
51+ see the [docs ](../ ../ how - to / data - strategy ) for more information .
9352
9453` ` ` tsx
9554let router = createBrowserRouter(routes, {
96- async dataStrategy({ matches , request }) {
97- const matchesToLoad = matches .filter ((m ) => m .shouldLoad );
98- const results: Record <string , DataStrategyResult > = {};
99- await Promise .all (
100- matchesToLoad .map (async (match ) => {
101- console .log (` Processing ${match .route .id } ` );
102- results [match .route .id ] = await match .resolve ();;
103- })
55+ async dataStrategy({
56+ matches,
57+ request,
58+ runClientMiddleware,
59+ }) {
60+ const matchesToLoad = matches.filter((m) =>
61+ m.shouldCallHandler(),
10462 );
105- return results ;
106- },
107- });
108- ```
109-
110- ** Middleware**
11163
112- Let's define a middleware on each route via [ ` handle ` ] ( ../../start/data/route-object#handle )
113- and call middleware sequentially first, then call all
114- [ ` loader ` ] ( ../../start/data/route-object#loader ) s in parallel - providing
115- any data made available via the middleware:
116-
117- ``` ts
118- const routes = [
119- {
120- id: " parent" ,
121- path: " /parent" ,
122- loader({ request }, context ) {
123- // ...
124- },
125- handle: {
126- async middleware({ request }, context ) {
127- context .parent = " PARENT MIDDLEWARE" ;
128- },
129- },
130- children: [
131- {
132- id: " child" ,
133- path: " child" ,
134- loader({ request }, context ) {
135- // ...
136- },
137- handle: {
138- async middleware({ request }, context ) {
139- context .child = " CHILD MIDDLEWARE" ;
140- },
141- },
142- },
143- ],
144- },
145- ];
146-
147- let router = createBrowserRouter (routes , {
148- async dataStrategy({ matches , params , request }) {
149- // Run middleware sequentially and let them add data to `context`
150- let context = {};
151- for (const match of matches ) {
152- if (match .route .handle ?.middleware ) {
153- await match .route .handle .middleware (
154- { request , params },
155- context
156- );
157- }
158- }
159-
160- // Run loaders in parallel with the `context` value
161- let matchesToLoad = matches .filter ((m ) => m .shouldLoad );
162- let results = await Promise .all (
163- matchesToLoad .map ((match , i ) =>
164- match .resolve ((handler ) => {
165- // Whatever you pass to `handler` will be passed as the 2nd parameter
166- // to your loader/action
167- return handler (context );
168- })
169- )
170- );
171- return results .reduce (
172- (acc , result , i ) =>
173- Object .assign (acc , {
174- [matchesToLoad [i ].route .id ]: result ,
64+ const results: Record<string, DataStrategyResult> = {};
65+ await runClientMiddleware(() =>
66+ Promise.all(
67+ matchesToLoad.map(async (match) => {
68+ results[match.route.id] = await match.resolve();
17569 }),
176- {}
70+ ),
17771 );
178- },
179- });
180- ```
181-
182- ** Custom Handler**
183-
184- It's also possible you don't even want to define a [ ` loader ` ] ( ../../start/data/route-object#loader )
185- implementation at the route level. Maybe you want to just determine the
186- routes and issue a single GraphQL request for all of your data? You can do
187- that by setting your ` route.loader=true ` so it qualifies as "having a
188- loader", and then store GQL fragments on ` route.handle ` :
189-
190- ``` ts
191- const routes = [
192- {
193- id: " parent" ,
194- path: " /parent" ,
195- loader: true ,
196- handle: {
197- gql: gql `
198- fragment Parent on Whatever {
199- parentField
200- }
201- ` ,
202- },
203- children: [
204- {
205- id: " child" ,
206- path: " child" ,
207- loader: true ,
208- handle: {
209- gql: gql `
210- fragment Child on Whatever {
211- childField
212- }
213- ` ,
214- },
215- },
216- ],
217- },
218- ];
219-
220- let router = createBrowserRouter (routes , {
221- async dataStrategy({ matches , params , request }) {
222- // Compose route fragments into a single GQL payload
223- let gql = getFragmentsFromRouteHandles (matches );
224- let data = await fetchGql (gql );
225- // Parse results back out into individual route level `DataStrategyResult`'s
226- // keyed by `routeId`
227- let results = parseResultsFromGql (data );
22872 return results;
22973 },
23074});
23175` ` `
232- </details >
23376
23477### opts .future
23578
@@ -336,7 +179,7 @@ individual routes prior to router initialization (and on any subsequently
336179added routes via ` route.lazy ` or ` patchRoutesOnNavigation ` ). This is
337180mostly useful for observability such as wrapping navigations , fetches ,
338181as well as route loaders /actions /middlewares with logging and /or performance
339- tracing .
182+ tracing . See the [ docs ](.. / .. / how - to / instrumentation ) for more information .
340183
341184` ` ` tsx
342185let router = createBrowserRouter(routes, {
0 commit comments