|
// 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"; |
|
|
|
// default cache, every location gets its own data, even at the same pathname |
|
function createLocationCache() { |
|
return { |
|
write({ cache, data, routeModule, location, params, routeId }) { |
|
cache[location.key] = cache[location.key] || {}; |
|
cache[location.key][routeId] = data; |
|
return cache; |
|
}, |
|
read({ cache, params, routeModule, location, routeId }) { |
|
return cache[location.key][routeId]; |
|
}, |
|
}; |
|
} |
|
|
|
// different locations but same pathname share the cache |
|
function createPathnameCache() { |
|
return { |
|
write({ cache, data, routeModule, location, params, routeId }) { |
|
cache[location.pathname] = cache[location.pathname] || {}; |
|
cache[location.pathname][routeId] = data; |
|
return cache; |
|
}, |
|
read({ cache, params, routeModule, location, routeId }) { |
|
return cache[location.pathname][routeId]; |
|
}, |
|
}; |
|
} |
|
|
|
// delegate to the route modules themselves, each has the ability to change the |
|
// entire cache, making it possible to normalize on writes so that data is |
|
// completely independant of locations |
|
function createRouteModuleDelegateCache() { |
|
// can facilitate a normalized cache with normalizr, each route module can use |
|
// the parts of the schema it needs so that the enitre schema isn't needed in |
|
// the initial bundle |
|
return { |
|
write({ cache, data, routeModule }) { |
|
return routeModule.writeData(cache, data); |
|
}, |
|
read({ cache, params, routeModule }) { |
|
return routeModule.readData(cache, params); |
|
}, |
|
}; |
|
} |
|
|
|
// In a component, the setter for useRouteData will end up calling `cache.write` |
|
function SomePage() { |
|
let [routeData, setRouteData] = useRouteData(); |
|
let someClickHandler = () => { |
|
// will go to cache.write so should be shaped like the result of the route loader |
|
let newData = {} |
|
setRouteData(newData) |
|
} |
|
} |
|
|
|
|
|
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"; |
|
|
|
export function writeData(cache, data) { |
|
let normalized = normalize(data, article); |
|
return Object.assign({}, cache, normalized.entities); |
|
} |
|
|
|
export function readData(cache, params) { |
|
return denormalize(params.articleId, article, cache); |
|
} |
|
|
|
export default function Article() { |
|
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" } |
|
// } |
|
// } |
|
// } |