Created
November 24, 2025 19:12
-
-
Save humphreyja/e94a5ab747b03a5fd42ef0ef54e7f1d4 to your computer and use it in GitHub Desktop.
How does Relay work?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Relay handles state by pretty much a context like store (or an external context like Redux). | |
| It's flat storage so every object must have a unique id (or key) or else it will overwrite other values. | |
| There's also an "optimistice" state that represents optimistic updates. These values are shown in priority | |
| to what is actually in the state but can also easily be rolled back. | |
| This is obviously a dumbed down version of relay so I didn't fully implement optimistic updates, but I know relay | |
| has the ability to roll back optimistic updates for a specific mutation instead of all updates like I have here. | |
| Also my "setter" is really rudimentary, it would cause a rerender on every value change instead of batching the updates. | |
| */ | |
| import { createContext } from 'react'; | |
| export const RelayContext = createContext({ state: {}, setter: () => null, optimisticSetter: () => null }); | |
| const RelayProvider = ({ children, api }) => { | |
| const [activeState, setActiveState] = useState({}); | |
| const [optimisticState, setOptimisticState] = useState({}); | |
| const setter = (object, key, value) => { | |
| const newState = { ...activeState }; | |
| newState[object.id] ||= {} | |
| newState[object.id][key] = value | |
| setActiveState(newState); | |
| } | |
| // same thing for optimistic setter | |
| const stateValue = { ...activeState, ..optimisticState }; | |
| return (<RelayContext.Provider value={{ state: stateValue, setter: setter, api }>{children}</RelayContext.Provider>); | |
| } | |
| export default RelayProvider; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { parseQueryIntoKeysAndTypes } from 'internal relay thing'; | |
| import { internalSuspend } from 'internal react thing'; | |
| /* | |
| Basically take an object like `{ user: { name: String }` and turn it into `{ user: { name: 'Jake' }}` | |
| */ | |
| function getDataFromState(askingForObject, state) { | |
| if (askingForObject === String) return state; | |
| if (askingForObject === Float) return state; | |
| // etc for all supported types | |
| const resolved = Object.keys(askingForObject).reduce((agg, key) => { | |
| return ({ | |
| ...agg, | |
| [key]: getDataFromState(askingForObject[key], state[key]); | |
| }) | |
| }, {}); | |
| return resolved; | |
| } | |
| // similar to above except it converts data into a call to change each value of a record | |
| // Like adding the "user" to the store and updating its name. | |
| function iterateOverEachKeyAndValue(data, callback) { | |
| // Won't implement this for brevity, but the callback will need a "record" which is simply just an object to relay with an ID. | |
| // All records are stored flat, so if another object has the same ID, it will overwrite a previous item. | |
| } | |
| const useLazyLoadQuery = (query, params, options = {}) => { | |
| const environment = useContext(RelayContext); | |
| const [fetched, setFetched] = useState({}); | |
| const parsedQuery = parseQueryIntoKeysAndTypes(query); // This will take your query and also add the "id" attribute to objects automatically. | |
| const result = getDataFromState(parsedQuery, environment.state); | |
| if (!fetched[JSON.stringify(params)] && options.fetchPolicy.includes('network')) { | |
| const ExecuteNetworkCall = async () => { | |
| const updatedData = await environment.api.fetch(query, params); | |
| // updating the store here, will trigger a rerender on this hook. | |
| iterateOverEachKeyAndValue(updatedData, (object, key, value) => environment.setter(object, key, value)); | |
| }; | |
| internalSuspend(ExecuteNetworkCall()); // IDk how react actually does this, but its definitely promise based. | |
| } | |
| return { data: result }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment