Skip to content

Commit

Permalink
feat: persist option (#105)
Browse files Browse the repository at this point in the history
* fix middleware order

* code clean up

* new persist option
  • Loading branch information
bluebill1049 authored Oct 27, 2021
1 parent 1d2cbe9 commit 42c186f
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 68 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"files": [
"dist"
],
"version": "4.0.0",
"version": "4.2.0-beta.1",
"main": "dist/little-state-machine.js",
"module": "dist/little-state-machine.es.js",
"unpkg": "dist/little-state-machine.umd.js",
Expand Down
2 changes: 1 addition & 1 deletion src/StateMachineContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ export function useStateMachineContext() {
}

return value;
}
}
7 changes: 0 additions & 7 deletions src/logic/getBrowserStoreData.ts

This file was deleted.

71 changes: 49 additions & 22 deletions src/logic/storeFactory.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
import { STORE_DEFAULT_NAME } from '../constants';
import getStoreData from './getBrowserStoreData';
import { MiddleWare, GlobalState } from '../types';

class StoreFactory {
public storageType: Storage;
public state: GlobalState = {};
public middleWares: MiddleWare[] = [];
function StoreFactory() {
let storageType: Storage;
let state: GlobalState = {};
let middleWares: MiddleWare[] = [];
let name = STORE_DEFAULT_NAME;

constructor(public name = STORE_DEFAULT_NAME) {
try {
this.storageType =
typeof sessionStorage !== 'undefined'
? window.sessionStorage
: ({} as Storage);
} catch {
this.storageType = {} as Storage;
}
try {
storageType =
typeof sessionStorage !== 'undefined'
? window.sessionStorage
: ({} as Storage);
} catch {
storageType = {} as Storage;
}

updateStore(defaultValues: GlobalState) {
this.state = getStoreData(this.storageType, this.name) || defaultValues;
}

updateMiddleWares(middleWares: MiddleWare[]) {
return (this.middleWares = middleWares);
}
return {
updateStore(defaultValues: GlobalState) {
try {
state = JSON.parse(storageType.getItem(name) || '') || defaultValues;
} catch {
state = defaultValues;
}
},
saveStore() {
storageType.setItem(name, JSON.stringify(state));
},
get middleWares() {
return middleWares;
},
set middleWares(wares: MiddleWare[]) {
middleWares = wares;
},
get state() {
return state;
},
set state(value) {
state = value;
},
get name() {
return name;
},
set name(value) {
name = value;
},
get storageType() {
return storageType;
},
set storageType(value) {
storageType = value;
},
};
}

export default new StoreFactory();
export default StoreFactory();
61 changes: 32 additions & 29 deletions src/stateMachine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ import {
AnyCallback,
AnyActions,
ActionsOutput,
PersistOptions,
} from './types';
import { STORE_ACTION_NAME, STORE_DEFAULT_NAME } from './constants';
import { STORE_ACTION_NAME } from './constants';

let persistOption: PersistOptions = 'onAction';

export function createStore(
defaultState: GlobalState,
options: StateMachineOptions = {
name: STORE_DEFAULT_NAME,
middleWares: [],
},
options: StateMachineOptions,
) {
options.name && (storeFactory.name = options.name);
options.storageType && (storeFactory.storageType = options.storageType);
options.middleWares && storeFactory.updateMiddleWares(options.middleWares);
if (options) {
options.name && (storeFactory.name = options.name);
options.storageType && (storeFactory.storageType = options.storageType);
options.middleWares && (storeFactory.middleWares = options.middleWares);
options.persist && (persistOption = options.persist);
}

if (process.env.NODE_ENV !== 'production') {
setUpDevTools(
Expand All @@ -33,33 +36,27 @@ export function createStore(
storeFactory.updateStore(defaultState);
}

function actionTemplate<TCallback extends AnyCallback>(
const actionTemplate = <TCallback extends AnyCallback>(
setState: React.Dispatch<React.SetStateAction<GlobalState>>,
callback: TCallback,
) {
return (payload: Parameters<TCallback>[1]) => {
if (process.env.NODE_ENV !== 'production') {
window[STORE_ACTION_NAME] = callback ? callback.name : '';
}
) => (payload: Parameters<TCallback>[1]) => {
if (process.env.NODE_ENV !== 'production') {
window[STORE_ACTION_NAME] = callback.name;
}

storeFactory.state = callback(storeFactory.state, payload);
storeFactory.state = callback(storeFactory.state, payload);

storeFactory.storageType.setItem(
storeFactory.name,
JSON.stringify(storeFactory.state),
if (storeFactory.middleWares) {
storeFactory.state = storeFactory.middleWares.reduce(
(currentValue, currentFunction) =>
currentFunction(currentValue, callback.name, payload) || currentValue,
storeFactory.state,
);
}

if (storeFactory.middleWares.length) {
storeFactory.state = storeFactory.middleWares.reduce(
(currentValue, currentFunction) =>
currentFunction(currentValue, callback.name, payload) || currentValue,
storeFactory.state,
);
}

setState(storeFactory.state);
};
}
setState(storeFactory.state);
persistOption === 'onAction' && storeFactory.saveStore();
};

export function useStateMachine<
TCallback extends AnyCallback,
Expand All @@ -81,6 +78,12 @@ export function useStateMachine<
),
);

React.useEffect(() => {
if (persistOption === 'beforeUnload') {
window.onbeforeunload = () => storeFactory.saveStore();
}
}, []);

return {
actions: actionsRef.current,
state,
Expand Down
22 changes: 14 additions & 8 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import * as React from 'react';

export interface GlobalState {};
export interface GlobalState {}

export type AnyCallback = (state: GlobalState, payload: any) => GlobalState
export type AnyCallback = (state: GlobalState, payload: any) => GlobalState;

export type AnyActions<TCallback> = Record<string, TCallback>;

export type ActionsOutput<TCallback extends AnyCallback, TActions extends AnyActions<TCallback>> = {
export type ActionsOutput<
TCallback extends AnyCallback,
TActions extends AnyActions<TCallback>
> = {
[K in keyof TActions]: (payload: Parameters<TActions[K]>[1]) => void;
}
};

export type StateMachineContextValue = {
state: GlobalState;
setState: React.Dispatch<React.SetStateAction<GlobalState>>
setState: React.Dispatch<React.SetStateAction<GlobalState>>;
};

export type MiddleWare = (
Expand All @@ -21,11 +24,14 @@ export type MiddleWare = (
callbackName: string,
) => GlobalState;

export type StateMachineOptions = {
export type PersistOptions = 'onAction' | 'none' | 'beforeUnload';

export type StateMachineOptions = Partial<{
name: string;
middleWares: MiddleWare[];
storageType?: Storage;
};
storageType: Storage;
persist: PersistOptions;
}>;

declare global {
interface Window {
Expand Down

0 comments on commit 42c186f

Please sign in to comment.