add createService (#6)
This commit is contained in:
@ -1,9 +1,7 @@
|
|||||||
import {format} from 'date-fns';
|
|
||||||
import {parse} from 'querystring';
|
|
||||||
import React, {memo} from 'react';
|
import React, {memo} from 'react';
|
||||||
import {numberParser, QueryParsers, stringParser, useQuery} from '../../../../common/hooks/useQuery';
|
import {numberParser, QueryParsers, stringParser, useQuery} from '../../../../common/hooks/useQuery';
|
||||||
import {QueryResponse, QueryResponseError} from '../../types';
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
const enum PersonType {
|
const enum PersonType {
|
||||||
One = 'one',
|
One = 'one',
|
||||||
Two = 'two'
|
Two = 'two'
|
||||||
@ -24,7 +22,7 @@ const parsers: QueryParsers<Person> = {
|
|||||||
const AuthResponsePage: React.FC = () => {
|
const AuthResponsePage: React.FC = () => {
|
||||||
const query = useQuery(parsers);
|
const query = useQuery(parsers);
|
||||||
return (
|
return (
|
||||||
<div>Auth Page</div>
|
<div>Auth Page {query.name}</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,16 +2,39 @@ import React, {memo} from 'react';
|
|||||||
import {AuthService} from '../../../../services/AuthService';
|
import {AuthService} from '../../../../services/AuthService';
|
||||||
import {useStream} from '../../../../utils/useStream';
|
import {useStream} from '../../../../utils/useStream';
|
||||||
import ComponentStream from '../component-stream/ComponentStream';
|
import ComponentStream from '../component-stream/ComponentStream';
|
||||||
|
import {createService} from '../../../../utils/createService';
|
||||||
|
|
||||||
|
const service = createService(1, {
|
||||||
|
changeWithStr: (state: number, val: string) => {
|
||||||
|
const parsedNumber = Number(val);
|
||||||
|
if (Number.isNaN(val)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedNumber;
|
||||||
|
},
|
||||||
|
add: (state: number) => {
|
||||||
|
return state + 1;
|
||||||
|
},
|
||||||
|
sub: (state: number) => {
|
||||||
|
return state - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const MainPage: React.FC = () => {
|
const MainPage: React.FC = () => {
|
||||||
const {isAuth} = useStream(AuthService.state$, AuthService.initState);
|
const {isAuth} = useStream(AuthService.state$, AuthService.initState);
|
||||||
const toggle = () => AuthService.handleChangeAuth(!isAuth);
|
const toggle = () => AuthService.handleChangeAuth(!isAuth);
|
||||||
|
const data = useStream(service.stream$, 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Main Page
|
Main Page
|
||||||
Auth: {isAuth ? 'yes' : 'no'}
|
Auth: {isAuth ? 'yes' : 'no'}
|
||||||
<button onClick={toggle}>click</button>
|
<button onClick={toggle}>click</button>
|
||||||
<ComponentStream />
|
<ComponentStream />
|
||||||
|
<div>{data}</div>
|
||||||
|
<button onClick={service.actions.add}>Add</button>
|
||||||
|
<button onClick={service.actions.sub}>Sub</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
36
src/utils/createService.ts
Normal file
36
src/utils/createService.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import {startWith} from '@most/core';
|
||||||
|
import {createAdapter} from '@most/adapter';
|
||||||
|
import {pipe} from 'fp-ts/es6/pipeable';
|
||||||
|
|
||||||
|
type ServiceAction<State, ValType> = (data: State, val?: ValType) => State;
|
||||||
|
|
||||||
|
type ServiceActions<State, T extends Record<string, ServiceAction<State, unknown>>> = {
|
||||||
|
[Key in keyof T]: T[Key] extends ServiceAction<State, infer D>
|
||||||
|
? D extends void | undefined
|
||||||
|
? () => State
|
||||||
|
: (val: D) => State
|
||||||
|
: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
export const createService = <State, Actions extends Record<string, ServiceAction<State, any>>>(
|
||||||
|
initData: State,
|
||||||
|
actions: Actions
|
||||||
|
) => {
|
||||||
|
const [handler, adapterStream$] = createAdapter<State>();
|
||||||
|
let currValue = initData;
|
||||||
|
const currStream$ = pipe(adapterStream$, startWith(initData));
|
||||||
|
const currActions = Object.entries(actions).reduce((acc, [key, func]) => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
(acc as any)[key] = (val: unknown) => {
|
||||||
|
currValue = func(currValue, val);
|
||||||
|
handler(currValue);
|
||||||
|
};
|
||||||
|
return acc;
|
||||||
|
}, {} as ServiceActions<State, Actions>);
|
||||||
|
return {
|
||||||
|
stream$: currStream$,
|
||||||
|
actions: currActions,
|
||||||
|
initialState: initData
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -3,7 +3,7 @@ import {Stream, Sink} from '@most/types';
|
|||||||
import {newDefaultScheduler} from '@most/scheduler';
|
import {newDefaultScheduler} from '@most/scheduler';
|
||||||
import {pending, RemoteData} from '@devexperts/remote-data-ts';
|
import {pending, RemoteData} from '@devexperts/remote-data-ts';
|
||||||
|
|
||||||
// eslint-disable-next-line no-empty-function
|
// eslint-disable-next-line
|
||||||
const emptyFunc = () => {};
|
const emptyFunc = () => {};
|
||||||
|
|
||||||
export const useStream = <T>(stream$: Stream<T>, defaultValue: T): T => {
|
export const useStream = <T>(stream$: Stream<T>, defaultValue: T): T => {
|
||||||
@ -22,7 +22,7 @@ export const useStream = <T>(stream$: Stream<T>, defaultValue: T): T => {
|
|||||||
return () => {
|
return () => {
|
||||||
effect$.dispose();
|
effect$.dispose();
|
||||||
};
|
};
|
||||||
}, []);
|
}, [stream$]);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user