From ee0257a557a7bedf4110dcbb50bda2207494b81d Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Thu, 10 Sep 2020 22:20:29 +0800 Subject: [PATCH] connectStores: Props first, States second React's way and the way it should be used. --- client/src/javascript/app.tsx | 20 ++++---- client/src/javascript/util/connectStores.tsx | 49 +++++++++++--------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/client/src/javascript/app.tsx b/client/src/javascript/app.tsx index 0993fb98..0fb191fe 100644 --- a/client/src/javascript/app.tsx +++ b/client/src/javascript/app.tsx @@ -6,7 +6,7 @@ import ReactDOM from 'react-dom'; import detectLocale from './util/detectLocale'; import * as i18n from './i18n/languages'; -import connectStores, {EventListenerDescriptor} from './util/connectStores'; +import connectStores from './util/connectStores'; import AppWrapper from './components/AppWrapper'; import AuthActions from './actions/AuthActions'; import EventTypes from './constants/EventTypes'; @@ -20,6 +20,10 @@ import UIStore from './stores/UIStore'; import '../sass/style.scss'; +interface FloodAppProps { + locale?: keyof typeof i18n.languages; +} + const initialize = (): void => { UIStore.registerDependency({ id: 'notifications', @@ -72,18 +76,14 @@ const appRoutes = ( ); -interface InjectedFloodAppProps { - locale: keyof typeof i18n.languages; -} - -class FloodApp extends React.Component { +class FloodApp extends React.Component { public componentDidMount(): void { initialize(); } public render(): React.ReactNode { let {locale} = this.props; - if (locale === 'auto' || !Object.prototype.hasOwnProperty.call(i18n.languages, locale)) { + if (locale == null || locale === 'auto' || !Object.prototype.hasOwnProperty.call(i18n.languages, locale)) { locale = detectLocale(); } @@ -95,14 +95,12 @@ class FloodApp extends React.Component { } } -const ConnectedFloodApp = connectStores(FloodApp, (): EventListenerDescriptor< - InjectedFloodAppProps ->[] => { +const ConnectedFloodApp = connectStores(FloodApp, () => { return [ { store: SettingsStore, event: EventTypes.SETTINGS_CHANGE, - getValue: (): InjectedFloodAppProps => { + getValue: () => { return { locale: SettingsStore.getFloodSettings('language'), }; diff --git a/client/src/javascript/util/connectStores.tsx b/client/src/javascript/util/connectStores.tsx index 491fff0f..651e7518 100644 --- a/client/src/javascript/util/connectStores.tsx +++ b/client/src/javascript/util/connectStores.tsx @@ -13,38 +13,41 @@ interface GenericStore { type Store = GenericStore | typeof AuthStore | typeof ClientStatusStore | typeof UIStore; -export interface EventListenerDescriptor { +export interface EventListenerDescriptor { store: Store; event: keyof typeof EventTypes | (keyof typeof EventTypes)[]; getValue: (props: { payload: unknown; - props: WrappedComponentProps; - state: DerivedState; + props: ConnectedComponentProps; + state: ConnectedComponentStates; store: Store; - }) => Partial; + }) => Partial; } -const connectStores = ( - InputComponent: React.JSXElementConstructor, +const connectStores = ( + InputComponent: React.JSXElementConstructor, getEventListenerDescriptors: ( - props: WrappedComponentProps, - ) => EventListenerDescriptor[], -): ((props: WrappedComponentProps) => React.ReactElement) => { - class ConnectedComponent extends React.Component { + props: ConnectedComponentProps, + ) => EventListenerDescriptor[], +): ((props: ConnectedComponentProps) => React.ReactElement) => { + class ConnectedComponent extends React.Component { private eventHandlersByStore: Map< Store, Set<{events: (keyof typeof EventTypes)[]; eventHandler: (payload: unknown) => void}> > = new Map(); - private constructor(props: WrappedComponentProps) { + private constructor(props: ConnectedComponentProps) { super(props); - this.state = getEventListenerDescriptors(props).reduce((state, eventListenerDescriptor): DerivedState => { - const {store, getValue} = eventListenerDescriptor; - return { - ...state, - ...getValue({state, props, store, payload: null}), - }; - }, ({} as unknown) as DerivedState); + this.state = getEventListenerDescriptors(props).reduce( + (state, eventListenerDescriptor): ConnectedComponentStates => { + const {store, getValue} = eventListenerDescriptor; + return { + ...state, + ...getValue({state, props, store, payload: null}), + }; + }, + ({} as unknown) as ConnectedComponentStates, + ); } public componentDidMount(): void { @@ -54,8 +57,8 @@ const connectStores = this.setState( - (state: DerivedState, props: WrappedComponentProps): DerivedState => - getValue({state, props, store, payload}) as DerivedState, + (state: ConnectedComponentStates, props: ConnectedComponentProps): ConnectedComponentStates => + getValue({state, props, store, payload}) as ConnectedComponentStates, ); const events = Array.isArray(event) ? event : [event]; @@ -91,11 +94,13 @@ const connectStores = ; + return ( + + ); } } - return (props: WrappedComponentProps): React.ReactElement => { + return (props: ConnectedComponentProps): React.ReactElement => { return ; }; };