|
// src/entry-browser.js |
|
import React from "react"; |
|
import { unstable_createRoot as createRoot } from "react-dom"; |
|
import Remix from "@remix-run/react/browser"; |
|
import App from "./components/App"; |
|
|
|
// create a custom cache by defining just write/read |
|
const cache = { |
|
// write gets called for each route that matched, so for the "copy" |
|
// operations we just won't call write at all |
|
write({ cache, data, routeModule, location, params, routeId }) { |
|
// create conventions on route modules so they can localize functionality |
|
return routeModule.writeData(cache, data); |
|
}, |
|
read({ cache, params, routeModule, location, routeId }) { |
|
return routeModule.readData(cache, params); |
|
}, |
|
}; |
|
|
|
createRoot(document, { hydrate: true }).render( |
|
// pass it in to remix, only need this in the browser because we can use |
|
// the cache.write when we hydrate from the client handoff |
|
<Remix cache={cache}> |
|
<App /> |
|
</Remix> |
|
); |
|
|
|
/////////////////////////////////// |
|
// src/routes/Article.js |
|
import React from "react"; |
|
import { normalize, denormalize } from "normalizr"; |
|
import { useRouteData } from "@remix-run/react"; |
|
import { article } from "../schema"; |
|
|
|
// app developer normalizes it and assigns to the cache, |
|
// ignoring location.key because they want normalized data for this page. |
|
// any routes that get articles will update the cache for all others, |
|
// so even on back clicks with no refetch the data is fresh (and mutations). |
|
|
|
// every write merges into the cache, so the cache is always the combined |
|
// "entities" of every normalize call from every route |
|
export function writeData(cache, data) { |
|
let normalized = normalize(data, article); |
|
Object.assign(cache, normalized.entities); |
|
} |
|
|
|
// get it all back denormalized |
|
export function readData(cache, params) { |
|
return denormalize(params.articleId, article, cache); |
|
} |
|
|
|
export default function Article() { |
|
// this will get denormalized data that's shared across all locations |
|
let data = useRouteData(); |
|
return <ArticlePage data={data} />; |
|
} |
|
|
|
// Data from the loader looks like this: |
|
// { |
|
// "id": "123", |
|
// "author": { |
|
// "id": "1", |
|
// "name": "Paul" |
|
// }, |
|
// "title": "My awesome blog post", |
|
// "comments": [ |
|
// { |
|
// "id": "324", |
|
// "commenter": { |
|
// "id": "2", |
|
// "name": "Nicole" |
|
// } |
|
// } |
|
// ] |
|
// } |
|
|
|
// normalizer normalizes it to this and they store `entities` as the cache |
|
// { |
|
// result: "123", |
|
// entities: { |
|
// "articles": { |
|
// "123": { |
|
// id: "123", |
|
// author: "1", |
|
// title: "My awesome blog post", |
|
// comments: [ "324" ] |
|
// } |
|
// }, |
|
// "users": { |
|
// "1": { "id": "1", "name": "Paul" }, |
|
// "2": { "id": "2", "name": "Nicole" } |
|
// }, |
|
// "comments": { |
|
// "324": { id: "324", "commenter": "2" } |
|
// } |
|
// } |
|
// } |