newContext
The newContext
function creates a context handler for managing key-value pairs in a stack of context objects, allowing retrieval and storage of values.
The getContextValue
function provides a mechanism to retrieve or initialize a value associated with a specific key within a stack of context objects. It uses interally the newContext
function.
Implementation
export function newContext<T>(
key: string,
required: boolean = false,
): (
...stack: Record<string, unknown>[]
) => [() => T | undefined, (value: T) => T] {
return (...stack: Record<string, unknown>[]) => [
function get() {
for (const s of stack) {
if (key in s) {
return s[key] as T;
}
}
if (required) {
throw new Error(`Value for the key "${key}" was not found.`);
}
return undefined;
},
function set(value: T) {
const [store] = stack;
if (!store) {
throw new Error("Stack is empty - no store");
}
store[key] = value;
return value;
},
];
}
export function getContextValue<T>(
key: string,
create: () => T,
): (...stack: Record<string, unknown>[]) => T {
const useContext = newContext<T>(key);
return (...stack: Record<string, unknown>[]) => {
const [get, set] = useContext(...stack);
return get() ?? set(create());
};
}
This method is particularly useful in scenarios where hierarchical context management is required, such as:
- Implementing scoped configurations in stateful applications.
- Managing hierarchical state values within finite state machines.
- Providing default values when a key is not found in the context stack.
Examples
newContext
method examples:
const stack = [{}, {}];
const useContext = newContext<number>("counter");
const [get, set] = useContext(...stack);
console.log(get()); // Outputs: undefined
set(42);
console.log(get()); // Outputs: 42
const stack = [{}, { level: 1 }];
const useLevelContext = newContext<number>("level");
const [getLevel, setLevel] = useLevelContext(...stack);
console.log(getLevel()); // Outputs: 1 (found in the second context object)
// Sets a new value in the first stack object:
setLevel(2);
console.log(getLevel()); // Outputs: 2
console.log(stack); // Outputs: [ { level: 2 }, { level: 1 } ]
delete stack[0].level; // Remove the 2
console.log(getLevel()); // Outputs: 1
console.log(stack); // Outputs: [ {}, { level: 1 } ]
getContextValue
method examples:
const stack = [{}, {}];
const getValue = getContextValue("myKey", () => "defaultValue");
console.log(getValue(...stack)); // Outputs: "defaultValue"
stack[0]["myKey"] = "customValue";
console.log(getValue(...stack)); // Outputs: "customValue"
const stack = [{ parent: "root" }, { child: "leaf" }];
const getChildValue = getContextValue("child", () => "defaultChild");
const getParentValue = getContextValue("parent", () => "defaultParent");
console.log(getChildValue(...stack)); // Outputs: "leaf"
console.log(getParentValue(...stack)); // Outputs: "root"
stack[1]["parent"] = "overriddenRoot";
console.log(getParentValue(...stack)); // Outputs: "overriddenRoot"
newContext
The newContext
function underpins the behavior of getContextValue
by providing getter and setter functions for a specific key.
function newContext<T>(
key: string,
required: boolean = false
): (
...stack: Record<string, unknown>[]
) => [get: () => T | undefined, set: (value: T) => T];
Parameters:
key
(string
): The key for which the getter and setter functions are created.required
(boolean
): The optional flag defining if the value associated with this key is required or it is optional; Theget
method rise an error if the required key was not found in the context.
Returns a function that:
- Accepts a stack of context objects (
Record<string, unknown>[]
). - Returns a tuple:
- Getter (
() => T | undefined
): Retrieves the value associated with the key from the stack, orundefined
if not found. - Setter (
(value: T) => T
): Sets the value in the top context object of the stack.
- Getter (
getContextValue method
function getContextValue<T>(
key: string,
create: () => T,
): (...stack: Record<string, unknown>[]) => T;
Parameters
key
(string
): The key whose value needs to be retrieved or initialized.create
(() => T
): A function that generates a default value if the key is not found in the context stack.
Returns a function that:
- Accepts a stack of context objects (
Record<string, unknown>[]
). - Returns the value associated with the provided key or initializes it using the
create
function if the key is not found.
Behavior Details
- The returned function iterates through the provided context stack in order.
- If the key is found in any object, its value is returned.
- If the key is not found, the
create
function is called to initialize the value. - The initialized value is stored in the first context object (top of the stack).
- Throws an error if the context stack is empty.