aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/framework/src/flux
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/framework/src/flux')
-rw-r--r--sdnr/wt/odlux/framework/src/flux/connect.tsx (renamed from sdnr/wt/odlux/framework/src/flux/connect.ts)94
-rw-r--r--sdnr/wt/odlux/framework/src/flux/store.ts16
2 files changed, 85 insertions, 25 deletions
diff --git a/sdnr/wt/odlux/framework/src/flux/connect.ts b/sdnr/wt/odlux/framework/src/flux/connect.tsx
index f54e4e0f0..09d30dae7 100644
--- a/sdnr/wt/odlux/framework/src/flux/connect.ts
+++ b/sdnr/wt/odlux/framework/src/flux/connect.tsx
@@ -15,13 +15,14 @@
* the License.
* ============LICENSE_END==========================================================================
*/
-import * as React from 'react';
-import * as PropTypes from 'prop-types';
+import React, { FC, useContext, createContext, useState, useEffect, useRef } from 'react';
-import { Dispatch } from '../flux/store';
+import { Dispatch } from './store';
import { ApplicationStore, IApplicationStoreState } from '../store/applicationStore';
+const LogLevel = +(localStorage.getItem('log.odlux.framework.flux.connect') || 0);
+
interface IApplicationStoreContext {
applicationStore: ApplicationStore;
}
@@ -38,12 +39,12 @@ interface IDispatchProps {
dispatch: Dispatch;
}
-type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
-
type ComponentDecoratorInfer<TMergedProps> = {
<TProps>(wrappedComponent: React.ComponentType<TProps & TMergedProps>): React.ComponentClass<Omit<TProps & TMergedProps, keyof TMergedProps>>;
};
+const ApplicationStoreContext = createContext<IApplicationStoreContext | undefined>(undefined);
+
export type Connect<TMapProps extends ((...args: any) => any) | undefined = undefined, TMapDispatch extends ((...args: any) => any) | undefined = undefined> =
(TMapProps extends ((...args: any) => any) ? ReturnType<TMapProps> : IApplicationStoreProps) &
(TMapDispatch extends ((...args: any) => any) ? ReturnType<TMapDispatch> : IDispatchProps);
@@ -75,9 +76,7 @@ export function connect<TProps, TStateProps, TDispatchProps>(
const injectApplicationStore = (WrappedComponent: React.ComponentType<TProps & (IApplicationStoreProps | TStateProps) & IDispatchProps>): React.ComponentType<TProps> => {
class StoreAdapter extends React.Component<TProps, {}> {
- public static contextTypes = { ...WrappedComponent.contextTypes, applicationStore: PropTypes.object.isRequired };
- context: IApplicationStoreContext;
-
+
render(): JSX.Element {
if (isWrappedComponentIsVersion1(WrappedComponent)) {
@@ -112,7 +111,7 @@ export function connect<TProps, TStateProps, TDispatchProps>(
this.forceUpdate();
}
}
-
+ StoreAdapter.contextType = ApplicationStoreContext;
return StoreAdapter;
}
@@ -138,24 +137,77 @@ export function connect<TProps, TStateProps, TDispatchProps>(
}
}
-interface ApplicationStoreProviderProps extends React.Props<ApplicationStoreProvider> {
+type ApplicationStoreProviderProps = {
applicationStore: ApplicationStore;
}
-export class ApplicationStoreProvider extends React.Component<ApplicationStoreProviderProps>
- implements /* React.ComponentLifecycle<ApplicationStoreProviderProps, any>, */ React.ChildContextProvider<IApplicationStoreContext> {
+export const ApplicationStoreProvider: FC<ApplicationStoreProviderProps> = (props) => {
+ const { applicationStore, children } = props;
- public static childContextTypes = { applicationStore: PropTypes.object.isRequired };
+ return (
+ <ApplicationStoreContext.Provider value={{ applicationStore }}>
+ {children}
+ </ApplicationStoreContext.Provider>
+ );
+};
- getChildContext(): IApplicationStoreContext {
- return {
- applicationStore: this.props.applicationStore
- };
+export const useApplicationStore = (): ApplicationStore => {
+ const context = useContext(ApplicationStoreContext);
+ if (context == null || context.applicationStore == null) {
+ throw new Error("Requires application store provider!")
}
+ return context.applicationStore
+};
- render(): JSX.Element {
- return React.Children.only(this.props.children) as any; //type error, fix when possible
+export const useSelectApplicationState = <TProp extends unknown >( selector: (state: IApplicationStoreState) => TProp, eqFunc = (a: TProp, b: TProp) => a === b ): TProp => {
+ const context = useContext(ApplicationStoreContext);
+ if (context == null || context.applicationStore == null) {
+ throw new Error("Requires application store provider!")
}
-}
+
+ const [propState, setPropState] = useState<TProp>(selector(context.applicationStore.state));
+
+ const selectorRef = useRef(selector);
+ selectorRef.current = selector;
+
+ const propStateRef = useRef({propState});
+ propStateRef.current.propState = propState;
+
+ useEffect(() => {
+ if (context == null || context.applicationStore == null) {
+ throw new Error("Requires application store provider!")
+ }
+
+ const changedHandler = () => {
+ const newState = selectorRef.current(context.applicationStore.state);
+ if (!eqFunc(newState, propStateRef.current.propState)) {
+ setPropState(newState);
+ }
+ };
+
+ if (LogLevel > 3) {
+ console.log("useSelectApplicationState: adding handler", changedHandler);
+ }
+
+ context.applicationStore.changed.addHandler(changedHandler);
+
+ return () => {
+ if (LogLevel > 3) {
+ console.log("useSelectApplicationState: removing handler", changedHandler);
+ }
-export default connect; \ No newline at end of file
+ context.applicationStore.changed.removeHandler(changedHandler);
+ }
+ }, [context]);
+
+ return propState;
+
+};
+
+export const useApplicationDispatch = (): Dispatch => {
+ const context = useContext(ApplicationStoreContext);
+ if (context == null || context.applicationStore == null) {
+ throw new Error("Requires application store provider!")
+ }
+ return context.applicationStore.dispatch;
+};
diff --git a/sdnr/wt/odlux/framework/src/flux/store.ts b/sdnr/wt/odlux/framework/src/flux/store.ts
index dd80ce7ba..347d295e0 100644
--- a/sdnr/wt/odlux/framework/src/flux/store.ts
+++ b/sdnr/wt/odlux/framework/src/flux/store.ts
@@ -20,6 +20,8 @@ import { Event } from "../common/event"
import { Action } from './action';
import { IActionHandler } from './action';
+const LogLevel = +(localStorage.getItem('log.odlux.framework.flux.store') || 0);
+
export interface Dispatch {
<TAction extends Action>(action: TAction): TAction;
}
@@ -28,8 +30,8 @@ export interface Enhancer<TStoreState> {
(store: Store<TStoreState>): Dispatch;
}
-class InitialisationAction extends Action { };
-const initialisationAction = new InitialisationAction();
+class InitializationAction extends Action { };
+const initializationAction = new InitializationAction();
export class Store<TStoreState> {
@@ -43,19 +45,22 @@ export class Store<TStoreState> {
this._isDispatching = false;
- this.changed = new Event<void>(); // sollten wir hier eventuell sogar den state mit übergeben ?
+ this.changed = new Event<void>();
this._actionHandler = actionHandler;
this._state = initialState as TStoreState;
if (enhancer) this._dispatch = enhancer(this);
- this._dispatch(initialisationAction);
+ this._dispatch(initializationAction);
}
public changed: Event<void>;
private _dispatch: Dispatch = <TAction extends Action>(payload: TAction): TAction => {
+ if (LogLevel > 2) {
+ console.log('Store::Dispatch - ', payload);
+ }
if (payload == null || !(payload instanceof Action)) {
throw new Error(
'Actions must inherit from type Action. ' +
@@ -76,6 +81,9 @@ export class Store<TStoreState> {
}
if (this._state !== oldState) {
+ if (LogLevel > 3) {
+ console.log('Store::Dispatch - state has changed', this._state);
+ }
this.changed.invoke();
}