Skip to content

Commit

Permalink
Merge branch 'use-local-state-store'
Browse files Browse the repository at this point in the history
  • Loading branch information
lostpebble committed Oct 1, 2020
2 parents 952dab8 + faef9b6 commit 7ed8199
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 33 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "pullstate",
"version": "1.16.1",
"version": "1.17.0",
"description": "Simple state stores using immer and React hooks",
"main": "dist/index.js",
"module": "dist/index.es.js",
"esnext": "dist/index.es.js",
"main:umd": "dist/pullstate.umd.js",
"main:umd:min": "dist/pullstate.umd.min.js",
"types": "dist/index.d.ts",
"files": [
"dist"
Expand Down Expand Up @@ -62,14 +63,17 @@
"@rollup/plugin-typescript": "^4.1.2",
"@rollup/plugin-node-resolve": "^9.0.0",
"rollup-plugin-typescript2": "^0.27.1",
"rollup-plugin-terser": "^7.0.2",
"rollup": "^1.31.1",
"terser": "^3.16.1",
"ts-jest": "^24.0.2",
"ts-loader": "^6.0.2",
"ts-node": "^8.2.0",
"typescript": "3.7.5",
"webpack": "^4.36.1",
"webpack-cli": "^3.3.6"
"webpack-cli": "^3.3.6",
"react": "^16.13.1",
"immer": "^7.0.1"
},
"peerDependencies": {
"immer": "^7.0.1",
Expand Down
11 changes: 11 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typescript from "rollup-plugin-typescript2";
import { terser } from "rollup-plugin-terser";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import pkg from "./package.json";
Expand Down Expand Up @@ -45,6 +46,16 @@ export default [{
"immer": "immer",
},
},
{
file: pkg["main:umd:min"],
format: "umd",
name: "pullstate",
globals: {
"react": "React",
"immer": "immer",
},
plugins: [terser()],
},
],
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})].filter(dep => dep !== "fast-deep-equal"),
}];
57 changes: 33 additions & 24 deletions src/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useStoreState } from "./useStoreState";
import { DeepKeyOfArray } from "./useStoreStateOpt-types";

import isEqual from "fast-deep-equal/es6";
import { useLocalStore } from "./useLocalStore";

enablePatches();

Expand Down Expand Up @@ -33,7 +34,7 @@ type TReactionCreator<S> = (store: Store<S>) => TRunReactionFunction;
function makeSubscriptionFunction<S, T>(
store: Store<S>,
watch: (state: S) => T,
listener: (watched: T, allState: S, previousWatched: T, uid?: string) => void
listener: (watched: T, allState: S, previousWatched: T, uid?: string) => void,
): TRunSubscriptionFunction {
let lastWatchState: T = watch(store.getRawState());

Expand All @@ -50,7 +51,7 @@ function makeSubscriptionFunction<S, T>(

function makeReactionFunctionCreator<S, T>(
watch: (state: S) => T,
reaction: TReactionFunction<S, T>
reaction: TReactionFunction<S, T>,
): TReactionCreator<S> {
return (store) => {
let lastWatchState: T = watch(store.getRawState());
Expand All @@ -63,7 +64,7 @@ function makeReactionFunctionCreator<S, T>(
if (forceRun || !isEqual(nextWatchState, lastWatchState)) {
if (store._optListenerCount > 0) {
const [nextState, patches, inversePatches] = produceWithPatches(currentState as any, (s: S) =>
reaction(nextWatchState, s as Draft<S>, currentState, lastWatchState)
reaction(nextWatchState, s as Draft<S>, currentState, lastWatchState),
) as any;

store._updateStateWithoutReaction(nextState);
Expand All @@ -76,7 +77,7 @@ function makeReactionFunctionCreator<S, T>(
} else {
if (store._patchListeners.length > 0) {
const [nextState, patches, inversePatches] = produceWithPatches(currentState as any, (s: S) =>
reaction(nextWatchState, s as Draft<S>, currentState, lastWatchState)
reaction(nextWatchState, s as Draft<S>, currentState, lastWatchState),
) as any;

if (patches.length > 0) {
Expand All @@ -86,8 +87,8 @@ function makeReactionFunctionCreator<S, T>(
} else {
store._updateStateWithoutReaction(
produce(currentState as any, (s: S) =>
reaction(nextWatchState, s as Draft<S>, currentState, lastWatchState)
) as any
reaction(nextWatchState, s as Draft<S>, currentState, lastWatchState),
) as any,
);
}
lastWatchState = nextWatchState;
Expand All @@ -110,7 +111,7 @@ const optPathDivider = "~._.~";

export type TStoreActionUpdate<S> = (
updater: TUpdateFunction<S> | TUpdateFunction<S>[],
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void,
) => void;

export type TStoreAction<S> = (update: TStoreActionUpdate<S>) => void;
Expand Down Expand Up @@ -236,7 +237,7 @@ export class Store<S = any> {

for (const keyedPath of listenerPathsKeyed) {
this.optimizedListenerPropertyMap[keyedPath] = this.optimizedListenerPropertyMap[keyedPath].filter(
(ord) => ord !== ordKey
(ord) => ord !== ordKey,
);
}

Expand Down Expand Up @@ -265,15 +266,15 @@ export class Store<S = any> {

return () => {
console.warn(
`Pullstate: Subscriptions made on the server side are not registered - so therefor this call to unsubscribe does nothing.`
`Pullstate: Subscriptions made on the server side are not registered - so therefor this call to unsubscribe does nothing.`,
);
};
}

createReaction<T>(
watch: (state: S) => T,
reaction: TReactionFunction<S, T>,
{ runNow = false, runNowWithSideEffects = false }: ICreateReactionOptions = {}
{ runNow = false, runNowWithSideEffects = false }: ICreateReactionOptions = {},
): () => void {
const creator = makeReactionFunctionCreator(watch, reaction);
this.reactionCreators.push(creator);
Expand Down Expand Up @@ -309,6 +310,14 @@ export class Store<S = any> {
return useStoreState(this, getSubState!, deps);
}

useLocalCopyInitial(deps?: ReadonlyArray<any>): Store<S> {
return useLocalStore(() => this.initialState, deps);
}

useLocalCopySnapshot(deps?: ReadonlyArray<any>): Store<S> {
return useLocalStore(this.currentState, deps);
}

/*action<A extends Array<any>>(
action: (...args: A) => TStoreAction<S>
): (...args: A) => TStoreAction<S> {
Expand All @@ -322,7 +331,7 @@ export class Store<S = any> {

batch(
updater: TUpdateFunction<S> | TUpdateFunction<S>[],
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void,
): void {
if (this.batchState === undefined) {
this.batchState = this.currentState;
Expand Down Expand Up @@ -354,7 +363,7 @@ export class Store<S = any> {

update(
updater: TUpdateFunction<S> | TUpdateFunction<S>[],
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void,
) {
update(this, updater, patchesCallback);
}
Expand Down Expand Up @@ -404,25 +413,25 @@ function getChangedPathsFromPatches(changePatches: Patch[], prev: IChangedPaths
function runUpdates<S>(
currentState: S,
updater: TUpdateFunction<S> | TUpdateFunction<S>[],
func: boolean
func: boolean,
): [S, Patch[], Patch[]] {
return func
? (produceWithPatches(currentState, (s: S) => (updater as TUpdateFunction<S>)(s as Draft<S>, currentState)) as any)
: ((updater as TUpdateFunction<S>[]).reduce(
([nextState, patches, inversePatches], currentValue) => {
const resp = produceWithPatches(nextState as any, (s: S) => currentValue(s as Draft<S>, nextState)) as any;
patches.push(...resp[1]);
inversePatches.push(...resp[2]);
return [resp[0], patches, inversePatches];
},
[currentState, [], []] as [S, Patch[], Patch[]]
) as [S, Patch[], Patch[]]);
([nextState, patches, inversePatches], currentValue) => {
const resp = produceWithPatches(nextState as any, (s: S) => currentValue(s as Draft<S>, nextState)) as any;
patches.push(...resp[1]);
inversePatches.push(...resp[2]);
return [resp[0], patches, inversePatches];
},
[currentState, [], []] as [S, Patch[], Patch[]],
) as [S, Patch[], Patch[]]);
}

export function update<S = any>(
store: Store<S>,
updater: TUpdateFunction<S> | TUpdateFunction<S>[],
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void
patchesCallback?: (patches: Patch[], inversePatches: Patch[]) => void,
) {
const currentState: S = store.getRawState();
const func = typeof updater === "function";
Expand Down Expand Up @@ -459,8 +468,8 @@ export function update<S = any>(
func
? (updater as TUpdateFunction<S>)(s as Draft<S>, currentState)
: (updater as TUpdateFunction<S>[]).reduce((previousValue, currentUpdater) => {
return produce(previousValue as any, (s: S) => currentUpdater(s as Draft<S>, previousValue)) as any;
}, currentState)
return produce(previousValue as any, (s: S) => currentUpdater(s as Draft<S>, previousValue)) as any;
}, currentState),
) as any;
}

Expand Down
6 changes: 3 additions & 3 deletions src/async-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ export interface IAsyncActionWatchOptions extends IAsyncActionBeckonOptions {
initiate?: boolean;
}

export interface IAsyncActionUseOptions extends IAsyncActionWatchOptions {
onSuccess?: () => void;
export interface IAsyncActionUseOptions<R> extends IAsyncActionWatchOptions {
onSuccess?: (result: R) => void;
}

export interface IAsyncActionRunOptions<S extends IPullstateAllStores = any> {
Expand Down Expand Up @@ -158,7 +158,7 @@ export interface IAsyncActionUpdateCachedOptions extends IAsyncActionSetCachedOp

export type TAsyncActionUse<A, R, T extends string> = (
args?: A,
options?: IAsyncActionUseOptions
options?: IAsyncActionUseOptions<R>
) => TUseResponse<R, T>;

export type TAsyncActionBeckon<A, R, T extends string> = (
Expand Down
4 changes: 2 additions & 2 deletions src/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,7 @@ further looping. Fix in your cacheBreakHook() is needed.`);
dormant = false,
key,
onSuccess,
}: IAsyncActionUseOptions = {}
}: IAsyncActionUseOptions<R> = {}
): TUseResponse<R, T> => {
// Set default options if initiate is true (beckon) or false (watch)
if (postActionEnabled == null) {
Expand All @@ -1021,7 +1021,7 @@ further looping. Fix in your cacheBreakHook() is needed.`);
if (onSuccess) {
useEffect(() => {
if (isSuccess && !dormant) {
onSuccess();
onSuccess(result.payload!);
}
}, [isSuccess]);
}
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import { EAsyncActionInjectType, InjectAsyncAction, TInjectAsyncActionProps } fr
import { InjectStoreStateOpt } from "./InjectStoreStateOpt";
import { TUseResponse } from "./async-types";
import { registerInDevtools } from "./reduxDevtools";
import { useLocalStore } from "./useLocalStore";

export * from "./async-types";

export {
useStoreState,
useStoreStateOpt,
useLocalStore,
update,
Store,
InjectStoreState,
Expand Down
22 changes: 22 additions & 0 deletions src/useLocalStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Store } from "./Store";
import { useRef } from "react";
import isEqual from "fast-deep-equal/es6";

function useLocalStore<S>(initialState: (() => S) | S, deps?: ReadonlyArray<any>): Store<S> {
const storeRef = useRef<Store<S>>();

if (storeRef.current == null) {
storeRef.current = new Store(typeof initialState === "function" ? (initialState as any)() : initialState);
}

if (deps !== undefined) {
const prevDeps = useRef<ReadonlyArray<any>>(deps);
if (!isEqual(deps, prevDeps)) {
storeRef.current = new Store(typeof initialState === "function" ? (initialState as any)() : initialState);
}
}

return storeRef.current;
}

export { useLocalStore };
21 changes: 21 additions & 0 deletions test/test.umd.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Test Minified</title>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/immer@7.0.1/dist/immer.umd.production.min.js"></script>
<script src="../dist/pullstate.umd.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1>Hi</h1>
<script type="text/javascript">
const TestStore = new pullstate.Store({
hi: "hello",
});

console.log(TestStore);

TestStore.subscribe(s => s.hi, (text) => console.log(text));
</script>
</body>
</html>
Loading

0 comments on commit 7ed8199

Please sign in to comment.