undefined on contexts that depend on each other

how can i fix this conflict? SavedProvider depends on useJsonData, and JsonDataProvider depends on useSaved.
export const [JsonDataProvider, useJsonData] = createContextProvider(() => {
// get the state synchronously
const [filePath, setFilePath] = useFilePath()!;
const [jsonPath, setJsonPath] = useJsonPath()!;
const [, setSaved] = useSaved()!;

const [jsonData, { mutate: setJsonData }] = createResource(async () => {
let jsonData: JsonValue = null;
const { args } = await getMatches();

// If user specified a file, set it as the current file
if ("file" in args && typeof args.file.value === "string") {
const resolvedPath = await path.resolve(args.file.value);
setFilePath(resolvedPath);
// Reset the json path as the file path has changed
setJsonPath([]);
}

// If a saved file path is set, load it
if (filePath()) {
try {
jsonData = await readFile(filePath()!);
} catch (error) {
dialog.message(String(error), { type: "error" });
// Remove the file path
setFilePath(null);
}
}

// Ensure the json path is pointing to an existing entry
if (jsonPath().length && !objectPath.has(jsonData, jsonPath()))
setJsonPath([]);

setSaved(true);

return jsonData;
});

return [jsonData, setJsonData] satisfies [
Resource<JsonValue>,
Setter<JsonValue>,
];
});

export const [SavedProvider, useSaved] = createContextProvider(() => {
const [jsonData] = useJsonData()!;

return createWritableMemo(() => {
jsonData();
return false;
});
});
export const [JsonDataProvider, useJsonData] = createContextProvider(() => {
// get the state synchronously
const [filePath, setFilePath] = useFilePath()!;
const [jsonPath, setJsonPath] = useJsonPath()!;
const [, setSaved] = useSaved()!;

const [jsonData, { mutate: setJsonData }] = createResource(async () => {
let jsonData: JsonValue = null;
const { args } = await getMatches();

// If user specified a file, set it as the current file
if ("file" in args && typeof args.file.value === "string") {
const resolvedPath = await path.resolve(args.file.value);
setFilePath(resolvedPath);
// Reset the json path as the file path has changed
setJsonPath([]);
}

// If a saved file path is set, load it
if (filePath()) {
try {
jsonData = await readFile(filePath()!);
} catch (error) {
dialog.message(String(error), { type: "error" });
// Remove the file path
setFilePath(null);
}
}

// Ensure the json path is pointing to an existing entry
if (jsonPath().length && !objectPath.has(jsonData, jsonPath()))
setJsonPath([]);

setSaved(true);

return jsonData;
});

return [jsonData, setJsonData] satisfies [
Resource<JsonValue>,
Setter<JsonValue>,
];
});

export const [SavedProvider, useSaved] = createContextProvider(() => {
const [jsonData] = useJsonData()!;

return createWritableMemo(() => {
jsonData();
return false;
});
});
im getting undefined behaviour no matter the depth/order the providers are put in on the component tree
14 Replies
REEEEE
REEEEE5mo ago
Not really possible, you'd probably have to combine the contexts Or introduce a higher context that receives the values and the other two read from that context, but that seems unnecessary
Danielius
DanieliusOP5mo ago
maybe i should implement the saved signal differently, but how 🤔
REEEEE
REEEEE5mo ago
Couldn't you move the writeable memo into the JsonDataProvider?
Danielius
DanieliusOP5mo ago
you mean to put the code for the memo in JsonDataProvider and also expose saved and setSaved from that context? hmm should i just create one combined context and expose it via a object? example
const [StateProvider, useState] = createContextProvider(() => {
...
return { jsonData, setJsonData, saved, setSaved, ... };
});
const [StateProvider, useState] = createContextProvider(() => {
...
return { jsonData, setJsonData, saved, setSaved, ... };
});
REEEEE
REEEEE5mo ago
That's how I would do it
Danielius
DanieliusOP5mo ago
fair enough think i will go with that then also this will make less imports across my app which is event better tbh
Danielius
DanieliusOP5mo ago
wow nice one...
export const [StateProvider, useState] = createContextProvider(() => {
const [filePath, setFilePath] = makePersisted(
// eslint-disable-next-line solid/reactivity
createSignal<string | null>(null),
{ name: "file-path" },
);
const [jsonPath, setJsonPath] = makePersisted(
// eslint-disable-next-line solid/reactivity
createSignal<JsonPath>([]),
{ name: "json-path" },
);
const [saved, setSaved] = createWritableMemo(() => {
jsonData();
return false;
});
const [jsonData, { mutate: setJsonData }] = createResource(initJsonData);

async function initJsonData() {
let jsonData: JsonValue = null;
const { args } = await getMatches();

// If user specified a file, set it as the current file
if ("file" in args && typeof args.file.value === "string") {
const resolvedPath = await path.resolve(args.file.value);
setFilePath(resolvedPath);
// Reset the json path as the file path has changed
setJsonPath([]);
}

// If a saved file path is set, load it
if (filePath()) {
try {
jsonData = await readFile(filePath()!);
} catch (error) {
dialog.message(String(error), { type: "error" });
// Remove the file path
setFilePath(null);
}
}

// Ensure the json path is pointing to an existing entry
if (jsonPath().length && !objectPath.has(jsonData, jsonPath()))
setJsonPath([]);

setSaved(true);

return jsonData;
}

return {
filePath,
setFilePath,
jsonPath,
setJsonPath,
saved,
setSaved,
jsonData,
setJsonData,
};
});
export const [StateProvider, useState] = createContextProvider(() => {
const [filePath, setFilePath] = makePersisted(
// eslint-disable-next-line solid/reactivity
createSignal<string | null>(null),
{ name: "file-path" },
);
const [jsonPath, setJsonPath] = makePersisted(
// eslint-disable-next-line solid/reactivity
createSignal<JsonPath>([]),
{ name: "json-path" },
);
const [saved, setSaved] = createWritableMemo(() => {
jsonData();
return false;
});
const [jsonData, { mutate: setJsonData }] = createResource(initJsonData);

async function initJsonData() {
let jsonData: JsonValue = null;
const { args } = await getMatches();

// If user specified a file, set it as the current file
if ("file" in args && typeof args.file.value === "string") {
const resolvedPath = await path.resolve(args.file.value);
setFilePath(resolvedPath);
// Reset the json path as the file path has changed
setJsonPath([]);
}

// If a saved file path is set, load it
if (filePath()) {
try {
jsonData = await readFile(filePath()!);
} catch (error) {
dialog.message(String(error), { type: "error" });
// Remove the file path
setFilePath(null);
}
}

// Ensure the json path is pointing to an existing entry
if (jsonPath().length && !objectPath.has(jsonData, jsonPath()))
setJsonPath([]);

setSaved(true);

return jsonData;
}

return {
filePath,
setFilePath,
jsonPath,
setJsonPath,
saved,
setSaved,
jsonData,
setJsonData,
};
});
No description
Danielius
DanieliusOP5mo ago
index.tsx:13 btw
No description
REEEEE
REEEEE5mo ago
move the createResource up above the writable memo
Danielius
DanieliusOP5mo ago
fixed. hmm how tf that work lmao thank you
REEEEE
REEEEE5mo ago
you were accessing jsonData in the writable memo before it was defined idk why js/ts doesn't warn when that happens but I've run into the same thing
Danielius
DanieliusOP5mo ago
ahh yes i see well, thats me finally done for the night lol. its 12:30 am💀 thanks 👍
REEEEE
REEEEE5mo ago
np
mdynnl
mdynnl5mo ago
yeah because it's inside a closure, we don't really know if it runs right away or next tick. it might be useful to have an eslint rule for this, before solid 2.0 lazy memo.
Want results from more Discord servers?
Add your server