Skip to content

Commit

Permalink
fix: support changing path (#1)
Browse files Browse the repository at this point in the history
* fix: support changing path

* update CHANGELOG
  • Loading branch information
dai-shi authored Jan 30, 2023
1 parent 81a0ac2 commit 51eb11d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change Log

## [Unreleased]
### Changed
- fix: support changing path #1

## [0.0.1] - 2023-01-23
### Added
Expand Down
42 changes: 24 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useReducer } from 'react';
import type { ReducerWithoutAction } from 'react';
import type { DispatchWithoutAction, Reducer } from 'react';
import { subscribe, snapshot } from 'valtio/vanilla';

type AsRef = { $$valtioRef: true };
Expand Down Expand Up @@ -31,6 +31,9 @@ const get = <T extends object, Path extends readonly unknown[]>(
return result;
};

// HACK the second parameter for snapshot() to path through promise
const handlePromise = <T>(x: Promise<T>) => x as unknown as T;

export function useValtio<State extends object>(proxy: State): Snapshot<State>;

export function useValtio<
Expand All @@ -42,36 +45,39 @@ export function useValtio<
State extends object,
Path extends readonly unknown[],
>(proxy: State, path: Path = [] as any) {
const getSlice = () =>
get(
// HACK the second parameter is to avoid handling promise
snapshot(proxy, (x) => x as any),
path,
);
type Result = ReturnType<typeof getSlice>;
const slice = get(snapshot(proxy, handlePromise), path);
const [[sliceFromReducer, proxyFromReducer], rerender] = useReducer<
ReducerWithoutAction<readonly [Result, State]>,
Reducer<readonly [typeof slice, State], boolean | undefined>,
undefined
>(
(prev) => {
const nextSlice = getSlice();
(prev, fromSelf?: boolean) => {
if (fromSelf) {
return [slice, proxy];
}
const nextSlice = get(snapshot(proxy, handlePromise), path);
if (Object.is(prev[0], nextSlice) && prev[1] === proxy) {
return prev;
}
return [nextSlice, proxy];
},
undefined,
() => [getSlice(), proxy],
() => [slice, proxy],
);
useEffect(() => {
const unsubscribe = subscribe(proxy, rerender, true);
rerender();
const unsubscribe = subscribe(
proxy,
rerender as DispatchWithoutAction,
true,
);
(rerender as DispatchWithoutAction)();
return unsubscribe;
}, [proxy]);
let slice = sliceFromReducer;
if (proxyFromReducer !== proxy) {
rerender();
slice = getSlice();
rerender(true);
return slice;
}
if (!Object.is(sliceFromReducer, slice)) {
rerender(true);
}
return slice;
return sliceFromReducer;
}

0 comments on commit 51eb11d

Please sign in to comment.