Skip to content

Instantly share code, notes, and snippets.

@humphreyja
Created November 24, 2025 19:12
Show Gist options
  • Select an option

  • Save humphreyja/e94a5ab747b03a5fd42ef0ef54e7f1d4 to your computer and use it in GitHub Desktop.

Select an option

Save humphreyja/e94a5ab747b03a5fd42ef0ef54e7f1d4 to your computer and use it in GitHub Desktop.
How does Relay work?
/*
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;
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