From 2109523a52ca6dd760e41bb82754f2bd15ba00e9 Mon Sep 17 00:00:00 2001 From: Chika Date: Tue, 1 Sep 2020 21:14:24 +0300 Subject: [PATCH] create mobx reacting effects --- package.json | 1 - public/index.html | 2 +- .../Containers/Calculation/Sections/index.ts | 64 ++++++++----------- src/client/Containers/Calculation/index.jsx | 14 ++-- src/client/Effects/index.ts | 21 ------ src/client/Elements/Input.jsx | 50 ++++++--------- src/client/Layout/index.jsx | 27 ++++---- .../CalculationStore/CalculationStore.ts | 24 ------- .../CalculationStore/Effects/autorun.ts | 11 ++++ .../CalculationStore/Effects/computed.js | 9 +++ .../stores/CalculationStore/Effects/index.js | 20 ++++++ .../CalculationStore/Effects/reaction.ts | 10 +++ .../stores/CalculationStore/Effects/when.ts | 10 +++ src/client/stores/CalculationStore/index.ts | 34 +++++++++- src/client/stores/CommonStore.ts | 4 +- src/client/stores/index.js | 12 ++++ src/client/stores/index.ts | 14 ---- src/client/tools/assignProps.js | 14 ++++ src/client/tools/runEffects.js | 13 ---- src/core/types/effect.ts | 25 +++++++- src/core/types/elements.ts | 5 +- 21 files changed, 214 insertions(+), 170 deletions(-) delete mode 100644 src/client/Effects/index.ts delete mode 100644 src/client/stores/CalculationStore/CalculationStore.ts create mode 100644 src/client/stores/CalculationStore/Effects/autorun.ts create mode 100644 src/client/stores/CalculationStore/Effects/computed.js create mode 100644 src/client/stores/CalculationStore/Effects/index.js create mode 100644 src/client/stores/CalculationStore/Effects/reaction.ts create mode 100644 src/client/stores/CalculationStore/Effects/when.ts create mode 100644 src/client/stores/index.js delete mode 100644 src/client/stores/index.ts create mode 100644 src/client/tools/assignProps.js delete mode 100644 src/client/tools/runEffects.js diff --git a/package.json b/package.json index 8076fe8..3adbdcb 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "normalize.css": "^8.0.1", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-redux": "^7.2.1", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "react-scripts": "3.4.3", diff --git a/public/index.html b/public/index.html index 70ec97a..9ced9cc 100644 --- a/public/index.html +++ b/public/index.html @@ -36,7 +36,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + Evo Calculator diff --git a/src/client/Containers/Calculation/Sections/index.ts b/src/client/Containers/Calculation/Sections/index.ts index 572b8e4..7003d4a 100644 --- a/src/client/Containers/Calculation/Sections/index.ts +++ b/src/client/Containers/Calculation/Sections/index.ts @@ -1,54 +1,46 @@ -import CalculationStore from "client/stores/CalculationStore"; -import withTitle from "client/hocs/withTitle"; -import { testEffectForPrice, testEffectForOne } from "client/Effects"; -import Input from "client/Elements/Input"; +import CalculationStore from 'client/stores/CalculationStore'; +import withTitle from 'client/hocs/withTitle'; +import Input from 'client/Elements/Input'; export default [ { - title: "FirstSection", + title: 'FirstSection', elements: [ { - name: "tbxPrice", - Component: withTitle("Price")(Input), + name: 'tbxPrice', + Component: withTitle('Price')(Input), props: { - placeholder: "Enter price", - sourceValueName: "price", - Effects: [testEffectForPrice], - }, + placeholder: 'Enter price', + sourceValueName: 'price' + } }, { - name: "tbxOne", - Component: withTitle("One")(Input), + name: 'tbxOne', + Component: withTitle('One')(Input), props: { - placeholder: "Enter one", - sourceValueName: "one", - Effects: [testEffectForOne], - }, + placeholder: 'Enter one', + sourceValueName: 'one' + } }, { - name: "tbxSecond", - Component: withTitle("Sum")(Input), + name: 'total', + Component: withTitle('Total')(Input), props: { - readonly: true, - getValue: (calculationStore: CalculationStore) => { - const price = calculationStore.getValue("price"); - const one = calculationStore.getValue("one"); - return parseInt(price) + parseInt(one); - }, - }, - }, - ], + computed: 'total' + } + } + ] }, { - title: "SecondSection", + title: 'SecondSection', elements: [ { - name: "priceonAnotherTab", - Component: withTitle("Price on another tab")(Input), + name: 'priceonAnotherTab', + Component: withTitle('Price on another tab')(Input), props: { - sourceValueName: "price", - }, - }, - ], - }, + sourceValueName: 'price' + } + } + ] + } ]; diff --git a/src/client/Containers/Calculation/index.jsx b/src/client/Containers/Calculation/index.jsx index d12b1cd..ae73e4c 100644 --- a/src/client/Containers/Calculation/index.jsx +++ b/src/client/Containers/Calculation/index.jsx @@ -1,9 +1,9 @@ -import Background from "client/Elements/Background"; -import React, { useState } from "react"; -import Sections from "./Sections"; +import Background from 'client/Elements/Background'; +import React, { useState } from 'react'; +import Sections from './Sections'; -import { Tabs } from "antd"; -import { Box } from "client/UIKit/grid"; +import { Tabs } from 'antd'; +import { Box } from 'client/UIKit/grid'; const { TabPane } = Tabs; const Calculation = () => { @@ -14,8 +14,8 @@ const Calculation = () => { {elements.map(({ Component, props }, ie) => { return ( - - + + ); })} diff --git a/src/client/Effects/index.ts b/src/client/Effects/index.ts deleted file mode 100644 index fa9e4ff..0000000 --- a/src/client/Effects/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import CalculationStore from "client/stores/CalculationStore"; -import { TEffect } from "core/types/effect"; - -export const testEffectForPrice: TEffect = async ( - calculationStore: CalculationStore -) => { - console.log("priceEffect"); - const price = calculationStore.getValue("price"); - if (parseInt(price) > 5000) { - calculationStore.setValue("one", 200); - } -}; - -export const testEffectForOne: TEffect = async ( - calculationStore: CalculationStore -) => { - const one = calculationStore.getValue("one"); - if (parseInt(one) > 1000) { - calculationStore.setValue("price", 100500); - } -}; diff --git a/src/client/Elements/Input.jsx b/src/client/Elements/Input.jsx index 022d60b..f4fb370 100644 --- a/src/client/Elements/Input.jsx +++ b/src/client/Elements/Input.jsx @@ -1,47 +1,35 @@ -import { Input as AntInput } from "antd"; -import { useStores } from "client/hooks/useStores"; -import runEffects from "client/tools/runEffects"; -import { observer } from "mobx-react"; -import React, { useEffect, useState } from "react"; -import { useDebounce } from "use-debounce"; +import { Input as AntInput } from 'antd'; +import { useStores } from 'client/hooks/useStores'; +import { observer } from 'mobx-react'; +import React, { useEffect, useState } from 'react'; +import { useDebounce } from 'use-debounce'; -const Input = ({ - readonly, - placeholder, - sourceValueName, - getValue, - Effects, -}) => { +const Input = ({ readonly, placeholder, sourceValueName, computed }) => { const { calculationStore } = useStores(); - const sourceValue = calculationStore.getValue(sourceValueName); const [currentValue, setCurrentValue] = useState(undefined); const [debouncedValue] = useDebounce(currentValue, 850); - // get Values - useEffect(() => { - if (sourceValueName) { - if (sourceValue) { - setCurrentValue(sourceValue); - } - } - }, [sourceValue, sourceValueName]); + const sourceValue = calculationStore.values[sourceValueName]; - // set Value to global store and run Effects + // get value from store useEffect(() => { - if (sourceValueName && debouncedValue) { + if (!computed) { + setCurrentValue(sourceValue); + } + }, [computed, sourceValue]); + + // set value to store + useEffect(() => { + if (!computed) { calculationStore.setValue(sourceValueName, debouncedValue); } - - if (Effects && Effects.length > 0) { - runEffects(Effects, calculationStore); - } - }, [debouncedValue]); + }, [calculationStore, computed, debouncedValue, sourceValueName]); return ( { + value={computed ? calculationStore[computed]() : currentValue} + onChange={e => { if (!readonly) { setCurrentValue(e.target.value); } diff --git a/src/client/Layout/index.jsx b/src/client/Layout/index.jsx index 08be2e8..d039693 100644 --- a/src/client/Layout/index.jsx +++ b/src/client/Layout/index.jsx @@ -1,9 +1,9 @@ -import paths from "client/common/paths"; -import { LogoText } from "client/Elements/Text"; -import colors from "client/UIKit/colors"; -import { Box, Flex } from "client/UIKit/grid"; -import React from "react"; -import { Route, Switch } from "react-router-dom"; +import paths from 'client/common/paths'; +import { LogoText } from 'client/Elements/Text'; +import colors from 'client/UIKit/colors'; +import { Box, Flex } from 'client/UIKit/grid'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; const Header = () => ( @@ -43,18 +43,17 @@ const Layout = () => ( const styles = { root: { - height: "100%", + height: '100%' }, - flex: { width: "100%" }, + flex: { width: '100%' }, header: { // backgroundColor: colors.violet.shades[700], - background: - "linear-gradient(90deg, rgba(69,0,198,1) 0%, rgba(205,0,231,1) 60%, rgba(163,2,184,1) 100%)", - height: "50px", - padding: "10px 12px", - paddingLeft: "20px", + background: 'linear-gradient(90deg, #1C01A9 0%, #3A0185 50%, #580161 100%)', + height: '50px', + padding: '10px 12px', + paddingLeft: '20px' // borderRadius: "0 0 10px 10px", - }, + } }; export default Layout; diff --git a/src/client/stores/CalculationStore/CalculationStore.ts b/src/client/stores/CalculationStore/CalculationStore.ts deleted file mode 100644 index 6304330..0000000 --- a/src/client/stores/CalculationStore/CalculationStore.ts +++ /dev/null @@ -1,24 +0,0 @@ -import initialStatuses from "core/config/initialStatuses"; -import initialValues from "core/config/initialValues"; -import { SourceValueNames } from "core/types/values"; -import { action, observable } from "mobx"; -import { Status } from "core/types/elements"; - -class CalculationStore { - values = observable(initialValues); - statuses = observable(initialStatuses); - - getValue = (sourceValueName: SourceValueNames) => - this.values[sourceValueName]; - setValue = action((sourceValueName: SourceValueNames, newValue: any) => { - this.values[sourceValueName] = newValue; - // TODO: Run effect here - }); - - getStatus = (elementName: string) => this.statuses[elementName]; - setStatus = action((elementName: string, status: Status) => { - this.statuses[elementName] = status; - }); -} - -export default CalculationStore; diff --git a/src/client/stores/CalculationStore/Effects/autorun.ts b/src/client/stores/CalculationStore/Effects/autorun.ts new file mode 100644 index 0000000..2fba7d5 --- /dev/null +++ b/src/client/stores/CalculationStore/Effects/autorun.ts @@ -0,0 +1,11 @@ +import { IAutorunEffect } from 'core/types/effect'; + +const autorunEffects: IAutorunEffect[] = [ + // calculationStore => () => { + // if (parseInt(calculationStore.values.price) > 25) { + // calculationStore.setValue('one', 100500); + // } + // } +]; + +export default autorunEffects; diff --git a/src/client/stores/CalculationStore/Effects/computed.js b/src/client/stores/CalculationStore/Effects/computed.js new file mode 100644 index 0000000..4810d71 --- /dev/null +++ b/src/client/stores/CalculationStore/Effects/computed.js @@ -0,0 +1,9 @@ +const computedEffects = { + total() { + const one = parseInt(this.values.one || 0); + const price = parseInt(this.values.price || 0); + return one + price; + } +}; + +export default computedEffects; diff --git a/src/client/stores/CalculationStore/Effects/index.js b/src/client/stores/CalculationStore/Effects/index.js new file mode 100644 index 0000000..949c0ab --- /dev/null +++ b/src/client/stores/CalculationStore/Effects/index.js @@ -0,0 +1,20 @@ +import CommonStore from '../../CommonStore'; +import { autorun, reaction, when } from 'mobx'; +import CalculationStore from '..'; +import autorunEffects from './autorun'; +import reactionEffects from './reaction'; +import whenEffects from './when'; + +autorunEffects.map(autorunEffect => + autorun(autorunEffect(CalculationStore, CommonStore)) +); + +reactionEffects.map(reactionEffectBuilder => { + const reactionEffect = reactionEffectBuilder(CalculationStore); + return reaction(reactionEffect.expression, reactionEffect.effect); +}); + +whenEffects.map(whenEffectBuilder => { + const whenEffect = whenEffectBuilder(CalculationStore); + return when(whenEffect.predicate, whenEffect.effect); +}); diff --git a/src/client/stores/CalculationStore/Effects/reaction.ts b/src/client/stores/CalculationStore/Effects/reaction.ts new file mode 100644 index 0000000..cca65f4 --- /dev/null +++ b/src/client/stores/CalculationStore/Effects/reaction.ts @@ -0,0 +1,10 @@ +import { IReactionEffect } from 'core/types/effect'; + +const reactionEffects: IReactionEffect[] = [ + calculationStore => ({ + expression: () => calculationStore.values.one, + effect: value => console.log(value) + }) +]; + +export default reactionEffects; diff --git a/src/client/stores/CalculationStore/Effects/when.ts b/src/client/stores/CalculationStore/Effects/when.ts new file mode 100644 index 0000000..ff4f613 --- /dev/null +++ b/src/client/stores/CalculationStore/Effects/when.ts @@ -0,0 +1,10 @@ +import { IWhenEffect } from 'core/types/effect'; + +const whenEffects: IWhenEffect[] = [ + calculationStore => ({ + predicate: () => parseInt(calculationStore.values.one) === 5, + effect: () => console.log(calculationStore.values.one) + }) +]; + +export default whenEffects; diff --git a/src/client/stores/CalculationStore/index.ts b/src/client/stores/CalculationStore/index.ts index 977e648..30c8a9a 100644 --- a/src/client/stores/CalculationStore/index.ts +++ b/src/client/stores/CalculationStore/index.ts @@ -1,3 +1,35 @@ -import CalculationStore from "./CalculationStore"; +import assignProperties from 'client/tools/assignProps'; +import initialStatuses from 'core/config/initialStatuses'; +import initialValues from 'core/config/initialValues'; +import { Status } from 'core/types/elements'; +import { SourceValueNames } from 'core/types/values'; +import { observable } from 'mobx'; +import computedEffects from './Effects/computed'; + +const CalculationStore = observable( + assignProperties( + { + values: initialValues, + statuses: initialStatuses, + + getValue(sourceValueName: SourceValueNames) { + return this.values[sourceValueName]; + }, + getStatus(elementName: string) { + return this.statuses[elementName]; + }, + + setValue(sourceValueName: SourceValueNames, newValue: any) { + this.values[sourceValueName] = newValue; + }, + setStatus(elementName: string, status: Status) { + this.statuses[elementName] = status; + } + }, + computedEffects + ) +); + +console.log(CalculationStore); export default CalculationStore; diff --git a/src/client/stores/CommonStore.ts b/src/client/stores/CommonStore.ts index db2fdeb..a42b08f 100644 --- a/src/client/stores/CommonStore.ts +++ b/src/client/stores/CommonStore.ts @@ -1,3 +1,5 @@ -class CommonStore {} +import { observable } from 'mobx'; + +const CommonStore = observable({}); export default CommonStore; diff --git a/src/client/stores/index.js b/src/client/stores/index.js new file mode 100644 index 0000000..db8157c --- /dev/null +++ b/src/client/stores/index.js @@ -0,0 +1,12 @@ +import CalculationStore from './CalculationStore'; +import CommonStore from './CommonStore'; +import './CalculationStore/Effects'; + +class RootStore { + constructor() { + this.calculationStore = CalculationStore; + this.commonStore = CommonStore; + } +} + +export default RootStore; diff --git a/src/client/stores/index.ts b/src/client/stores/index.ts deleted file mode 100644 index e6d4fb6..0000000 --- a/src/client/stores/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import CalculationStore from "./CalculationStore"; -import CommonStore from "client/stores/CommonStore"; - -class RootStore { - calculationStore: CalculationStore; - commonStore: CommonStore; - - constructor() { - this.calculationStore = new CalculationStore(); - this.commonStore = new CommonStore(); - } -} - -export default RootStore; diff --git a/src/client/tools/assignProps.js b/src/client/tools/assignProps.js new file mode 100644 index 0000000..d0def4c --- /dev/null +++ b/src/client/tools/assignProps.js @@ -0,0 +1,14 @@ +function assignProperties(target, ...sources) { + sources.forEach(source => { + Object.defineProperties( + target, + Object.keys(source).reduce((descriptors, key) => { + descriptors[key] = Object.getOwnPropertyDescriptor(source, key); + return descriptors; + }, {}) + ); + }); + return target; +} + +export default assignProperties; diff --git a/src/client/tools/runEffects.js b/src/client/tools/runEffects.js deleted file mode 100644 index 1f685e2..0000000 --- a/src/client/tools/runEffects.js +++ /dev/null @@ -1,13 +0,0 @@ -async function runEffects(effects, calculationStore) { - if (effects && effects.length > 0) { - for (let effect of effects) { - try { - await effect(calculationStore); - } catch (error) { - throw error; - } - } - } -} - -export default runEffects; diff --git a/src/core/types/effect.ts b/src/core/types/effect.ts index 705bd9f..d2585e9 100644 --- a/src/core/types/effect.ts +++ b/src/core/types/effect.ts @@ -1,3 +1,24 @@ -import CalculationStore from "client/stores/CalculationStore"; +import CalculationStore from 'client/stores/CalculationStore'; +import CommonStore from 'client/stores/CommonStore'; +import { IReactionPublic, Lambda } from 'mobx'; -export type TEffect = (calculationStore: CalculationStore) => Promise; +type TCalculationStore = typeof CalculationStore; +type TCommonStore = typeof CommonStore; + +export interface IAutorunEffect { + (CalculationStore: TCalculationStore, CommonStore?: TCommonStore): () => void; +} + +export interface IReactionEffect { + (CalculationStore: TCalculationStore): { + expression: (r: IReactionPublic) => any; + effect: (arg: any, r: IReactionPublic) => void; + }; +} + +export interface IWhenEffect { + (CalculationStore: TCalculationStore): { + predicate: () => boolean; + effect: Lambda; + }; +} diff --git a/src/core/types/elements.ts b/src/core/types/elements.ts index c894735..aaa55c0 100644 --- a/src/core/types/elements.ts +++ b/src/core/types/elements.ts @@ -1,7 +1,4 @@ -import CalculationStore from "client/stores/CalculationStore"; -import { SourceValueNames } from "core/types/values"; - export enum Status { Default, - Disabled, + Disabled }