useOptic
ts
ts
This hook allows your components to subscribe to an optic.
It returns a tuple with the value, and a set of options.
The component re-renders each time the focused value changes.
tsxuseOptic ,createState } from "@optics/react";constcountOptic =createState (42);constMyCount = () => {const [count ] =useOptic (countOptic );// set new count valuecountOptic .set (100);return <div >count: {count }</div >;};
tsxuseOptic ,createState } from "@optics/react";constcountOptic =createState (42);constMyCount = () => {const [count ] =useOptic (countOptic );// set new count valuecountOptic .set (100);return <div >count: {count }</div >;};
Options
The hook can take a set of options as a second argument.
- denormalize
boolean default: falseIf set to true the value returned by useOptic is denormalized: the optics referenced in the value are replaced by their respective focused values.
tsxpremiumPlanOptic =createState ({name : "Premium",price : 100,});constuserOptic =createState ({name : "John",plan :premiumPlanOptic ,});const [user ] =useOptic (userOptic , {denormalize : true });
tsxpremiumPlanOptic =createState ({name : "Premium",price : 100,});constuserOptic =createState ({name : "John",plan :premiumPlanOptic ,});const [user ] =useOptic (userOptic , {denormalize : true });
Result
The hook returns a result object as second element of the tuple with the following properties:
tsxsetState ,whenFocused ,whenType ,getOptics ,getOpticsFromMapping }] =useOptic (optic );
tsxsetState ,whenFocused ,whenType ,getOptics ,getOpticsFromMapping }] =useOptic (optic );
- setState
Dispatch<SetStateAction<T>>
An update function for the optic with a stable reference.
Equivalent to: useCallback((value) => optic.set(value), [optic]).
- whenFocused
<R>(then: (totalOptic: Optic<T>) => R) => R | null
This function lets you narrow a partial optic (an optic that might be unfocused)
to a total optic (an optic that's always focused, the default behavior).
The narrowed optic is provided as parameter of the callback, the latter only runs if the narrowing succeeds (if the optic is focused on a value).
tsxwhenFocused }] =useOptic (userPartialOptic );<>{whenFocused ((userTotalOptic ) => (<UserCard userOptic ={userTotalOptic } />))}</>;
tsxwhenFocused }] =useOptic (userPartialOptic );<>{whenFocused ((userTotalOptic ) => (<UserCard userOptic ={userTotalOptic } />))}</>;
It can also narrow the type of the focused value from nullable to non-nullable:
tsxwhenFocused }] =useOptic (nullableStringOptic );whenFocused ((stringOptic ) => {});
tsxwhenFocused }] =useOptic (nullableStringOptic );whenFocused ((stringOptic ) => {});
The function returns null if the optic is unfocused.
- whenType
<U extends T>(refine: (value: T) => U | false) => <R>(then: (narrowedOptic: Optic<U>) => R) => R | null
This function lets you narrow the type of the focused value in the optic.
It takes a first callback that narrows the value then returns it,
and a second callback that only runs if the narrowing succeeds and that has the narrowed optic provided as parameter.
tsxwhenType }] =useOptic (stringOrNumberOptic );<>{whenType ((value ) => typeofvalue === "number" &&value )((numberOptic ) => (<NumericInput numberOptic ={numberOptic } />))}{whenType ((value ) => typeofvalue === "string" &&value )((stringOptic ) => (<Input stringOptic ={stringOptic } />))}</>;
tsxwhenType }] =useOptic (stringOrNumberOptic );<>{whenType ((value ) => typeofvalue === "number" &&value )((numberOptic ) => (<NumericInput numberOptic ={numberOptic } />))}{whenType ((value ) => typeofvalue === "string" &&value )((stringOptic ) => (<Input stringOptic ={stringOptic } />))}</>;
The function returns null if the narrowing fails.
It can also take an explicit type guard as first argument:
tsxisFish (pet :Fish |Bird ):pet isFish {return (pet asFish ).swim !==undefined ;}const [, {whenType }] =useOptic (petOptic );whenType (isFish )((fishOptic ) => {});
tsxisFish (pet :Fish |Bird ):pet isFish {return (pet asFish ).swim !==undefined ;}const [, {whenType }] =useOptic (petOptic );whenType (isFish )((fishOptic ) => {});
- getOptics
(getKey: (t: T[number]) => string) => readonly [key: string, optic: Optic<T[number]>][];
Only available if the optic is focused on an array, this function derives a new optic for each element of the array.
An element of the array will always have the same associated optic, even if the array is reordered, appended, prepended, ...
This is thanks to the getKey function that you provide, which returns a unique key for each element of the array.
tsxgetOptics }] =useOptic (usersOptic );<>{getOptics ((user ) =>user .id ).map (([key ,userOptic ]) => (<User key ={key }userOptic ={userOptic } />))}</>;
tsxgetOptics }] =useOptic (usersOptic );<>{getOptics ((user ) =>user .id ).map (([key ,userOptic ]) => (<User key ={key }userOptic ={userOptic } />))}</>;
Since keys serve the same purpose as in React, you can reuse the generated key and pass it to the key prop of the component.
- getOpticsFromMapping
(getKey: (t: T) => string) => readonly [key: string, optic: Optic<T>][];
This function is similar to getOptics, but it derive the optics from the values of a mapped optics instead of an array.
tsxgetOpticsFromMapping }] =useOptic (userMappedOptic );<>{getOpticsFromMapping ((user ) =>user .id ).map (([key ,userOptic ]) => (<User key ={key }userOptic ={userOptic } />))}</>;
tsxgetOpticsFromMapping }] =useOptic (userMappedOptic );<>{getOpticsFromMapping ((user ) =>user .id ).map (([key ,userOptic ]) => (<User key ={key }userOptic ={userOptic } />))}</>;