xref: /MusicFree/src/utils/stateMapper.ts (revision 39ac60f7dbc1bdc5845915557793b2147e7a7f36)
1import {useEffect, useState} from 'react';
2
3export default class StateMapper<T> {
4    private getFun: () => T;
5    private cbs: Set<Function> = new Set([]);
6    constructor(getFun: () => T) {
7        this.getFun = getFun;
8    }
9
10    notify = () => {
11        this.cbs.forEach(_ => _?.());
12    };
13
14    useMappedState = () => {
15        const [_state, _setState] = useState<T>(this.getFun);
16        const updateState = () => {
17            _setState(this.getFun());
18        };
19        useEffect(() => {
20            this.cbs.add(updateState);
21            return () => {
22                this.cbs.delete(updateState);
23            };
24        }, []);
25        return _state;
26    };
27}
28
29type UpdateFunc<T> = (prev: T) => T;
30
31export class GlobalState<T> {
32    private value: T;
33    private stateMapper: StateMapper<T>;
34
35    constructor(initValue: T) {
36        this.value = initValue;
37        this.stateMapper = new StateMapper(this.getValue);
38    }
39
40    public getValue = () => {
41        return this.value;
42    };
43
44    public useValue = () => {
45        return this.stateMapper.useMappedState();
46    };
47
48    public setValue = (value: T | UpdateFunc<T>) => {
49        let newValue: T;
50        if (typeof value === 'function') {
51            newValue = (value as UpdateFunc<T>)(this.value);
52        } else {
53            newValue = value;
54        }
55
56        this.value = newValue;
57        this.stateMapper.notify();
58    };
59}
60