fix useimmutable

This commit is contained in:
Michael Fatemi 2021-07-17 17:41:31 -04:00
parent c78d03a6a1
commit 6f2d53270d
2 changed files with 33 additions and 20 deletions

View File

@ -2,17 +2,18 @@ import useImmutable from './useImmutable';
export default function UseImmutableTest() { export default function UseImmutableTest() {
const [imm] = useImmutable({ const [imm] = useImmutable({
x: 0, index: 0,
y: 0, array: [{ count: 0 }, { count: 1 }, { count: 2 }],
z: { a: 1, b: 2, c: [0, 1, 2] },
}); });
return ( return (
<div> <div>
{JSON.stringify(imm)} {JSON.stringify(imm)}
<br /> <br />
<button onClick={() => imm.z.a++}>Increment</button> <button onClick={() => imm.index--}>Previous</button>
<button onClick={() => imm.z.c.push(imm.z.c.length)}>Push</button> <button onClick={() => imm.index++}>Next</button>
<button onClick={() => imm.array[imm.index].count++}>Increment</button>
<button onClick={() => imm.array[imm.index].count--}>Decrement</button>
</div> </div>
); );
} }

View File

@ -66,27 +66,41 @@ function createEdgeForArray<T extends PlainJS>(
value: PlainJSArray<T>, value: PlainJSArray<T>,
setValue: Dispatch<SetStateAction<PlainJSArray<T>>> setValue: Dispatch<SetStateAction<PlainJSArray<T>>>
) { ) {
const edges = {} as Record<number, T>;
const set = (property: number, next: SetStateAction<T>) => {
const current = value[property];
const nextValue = typeof next === 'function' ? next(current) : next;
setValue((value) => [
...value.slice(0, property),
nextValue,
...value.slice(property + 1),
]);
};
return new Proxy(value, { return new Proxy(value, {
set: (target, property, value) => { set: (target, property, value) => {
if (typeof property === 'number') { if (typeof property === 'number') {
const set = (next: SetStateAction<T>) => { set(property, value);
const v = typeof next === 'function' ? next(value) : next;
const edge = createEdge(v, set);
setValue((v) => [
...v.slice(0, property),
edge,
...v.slice(property + 1),
]);
};
set(value);
} }
return true; return true;
}, },
// @ts-expect-error // @ts-expect-error
get: (target, property: keyof PlainJSArray<T>[]) => { get: (target, property: keyof PlainJSArray<T>[]) => {
if (typeof property === 'number') { if (
return target[property]; typeof property === 'number' ||
(typeof property === 'string' && /\d+/.test(property))
) {
property = +property;
if (property in edges) {
return edges[property];
}
const item = target[property];
const setThis = set.bind(null, property);
const edge = createEdge(item, setThis);
edges[property] = edge;
return edge;
} else { } else {
// @ts-ignore // @ts-ignore
if (inPlaceArrayOperations.includes(property)) { if (inPlaceArrayOperations.includes(property)) {
@ -133,7 +147,5 @@ export default function useImmutable<T extends PlainJS>(
const edge = useMemo(() => createEdge(value, setValue), [value]); const edge = useMemo(() => createEdge(value, setValue), [value]);
console.log('rerendered useImmutable');
return [edge, setValue]; return [edge, setValue];
} }