-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RRR Step 3 - Hydration #4703
RRR Step 3 - Hydration #4703
Changes from all commits
a76020a
e469db7
26dc999
761838d
7dd3269
a2a7526
38fa3c7
75400a1
d4c393a
2627c44
1d079f3
cc2b341
aa774f4
6ed9f3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,7 +89,16 @@ module.exports = { | |
"no-new-object": WARN, | ||
"no-octal": WARN, | ||
"no-redeclare": ERROR, | ||
"no-restricted-imports": [WARN, ...replaceRemixImportsOptions], | ||
"no-restricted-imports": [ | ||
WARN, | ||
...replaceRemixImportsOptions, | ||
{ | ||
importNames: ["useTransition"], | ||
message: | ||
"useTransition is deprecated in favor of useNavigation as of v1.9.0.", | ||
name: "@remix-run/react", | ||
}, | ||
], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linter deprecation warning for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets bulk include deprecation warnings in a subsequent release There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3 types of deprecation warnings: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove for now, we may add back in for the stable release |
||
"no-script-url": WARN, | ||
"no-self-assign": WARN, | ||
"no-self-compare": WARN, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,61 @@ | ||
import type { BrowserHistory, Action, Location } from "@remix-run/router"; | ||
import { createBrowserHistory } from "@remix-run/router"; | ||
import type { HydrationState, Router } from "@remix-run/router"; | ||
import type { ReactElement } from "react"; | ||
import * as React from "react"; | ||
import { createBrowserRouter, RouterProvider } from "react-router-dom"; | ||
|
||
import { RemixEntry } from "./components"; | ||
import type { EntryContext } from "./entry"; | ||
import { RemixContext } from "./components"; | ||
import type { EntryContext, FutureConfig } from "./entry"; | ||
import { deserializeErrors } from "./errors"; | ||
import type { RouteModules } from "./routeModules"; | ||
import { createClientRoutes } from "./routes"; | ||
|
||
/* eslint-disable prefer-let/prefer-let */ | ||
declare global { | ||
var __remixContext: EntryContext; | ||
var __remixContext: { | ||
state: HydrationState; | ||
future: FutureConfig; | ||
}; | ||
var __remixRouteModules: RouteModules; | ||
var __remixManifest: EntryContext["manifest"]; | ||
} | ||
/* eslint-enable prefer-let/prefer-let */ | ||
|
||
export interface RemixBrowserProps {} | ||
|
||
interface Update { | ||
action: Action; | ||
location: Location; | ||
} | ||
let router: Router; | ||
|
||
/** | ||
* The entry point for a Remix app when it is rendered in the browser (in | ||
* `app/entry.client.js`). This component is used by React to hydrate the HTML | ||
* that was received from the server. | ||
*/ | ||
export function RemixBrowser(_props: RemixBrowserProps): ReactElement { | ||
let historyRef = React.useRef<BrowserHistory>(); | ||
if (historyRef.current == null) { | ||
historyRef.current = createBrowserHistory({ window, v5Compat: true }); | ||
} | ||
|
||
let history = historyRef.current; | ||
let [state, dispatch] = React.useReducer( | ||
(_: Update, update: Update) => update, | ||
{ | ||
action: history.action, | ||
location: history.location, | ||
if (!router) { | ||
let routes = createClientRoutes( | ||
window.__remixManifest.routes, | ||
window.__remixRouteModules | ||
); | ||
|
||
let hydrationData = window.__remixContext.state; | ||
if (hydrationData && hydrationData.errors) { | ||
hydrationData = { | ||
...hydrationData, | ||
errors: deserializeErrors(hydrationData.errors), | ||
}; | ||
} | ||
); | ||
|
||
React.useLayoutEffect(() => history.listen(dispatch), [history]); | ||
|
||
let entryContext = window.__remixContext; | ||
entryContext.manifest = window.__remixManifest; | ||
entryContext.routeModules = window.__remixRouteModules; | ||
// In the browser, we don't need this because a) in the case of loader | ||
// errors we already know the order and b) in the case of render errors | ||
// React knows the order and handles error boundaries normally. | ||
entryContext.appState.trackBoundaries = false; | ||
entryContext.appState.trackCatchBoundaries = false; | ||
router = createBrowserRouter(routes, { hydrationData }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create our client side |
||
} | ||
|
||
return ( | ||
<RemixEntry | ||
context={entryContext} | ||
action={state.action} | ||
location={state.location} | ||
navigator={history} | ||
/> | ||
<RemixContext.Provider | ||
value={{ | ||
manifest: window.__remixManifest, | ||
routeModules: window.__remixRouteModules, | ||
future: window.__remixContext.future, | ||
}} | ||
> | ||
<RouterProvider router={router} fallbackElement={null} /> | ||
</RemixContext.Provider> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Render |
||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing integration tests from
dev
change slightly since we use new private API on location state to detecttype