index.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {
  2. createContext,
  3. useContext,
  4. useReducer,
  5. useEffect,
  6. ReactNode,
  7. Dispatch
  8. } from "react";
  9. import {
  10. ConfigType
  11. } from "../types";
  12. class NCoreContext<T extends {} | undefined, K extends ConfigType<T>> {
  13. // context:
  14. // @ts-ignore // TODO: Type problem will be fix.
  15. stateContext = createContext<T>({
  16. });
  17. // variables:
  18. state: T;
  19. setState: (state: Partial<T> | any) => void = () => {
  20. };
  21. subscribers: Array<{
  22. func: (params: any, state: T) => void;
  23. key: string;
  24. }> = [];
  25. config: K;
  26. // hooks:
  27. useContext = (): T => useContext(this.stateContext);
  28. constructor(state: T, config: K) {
  29. // set initial state:
  30. this.state = state;
  31. this.config = config;
  32. if(config.isSaveState && config.onSetStateFromStorage) {
  33. const savedState = config.onSetStateFromStorage();
  34. if(savedState) {
  35. this.state = {
  36. ...state,
  37. ...savedState
  38. };
  39. }
  40. }
  41. }
  42. // event emitters:
  43. emit = (params: any, state: T) => {
  44. this.subscribers.forEach(subscriber => {
  45. subscriber.func(params, state);
  46. });
  47. };
  48. emitWithKey = (key: string, payload?: any) => {
  49. this.subscribers.forEach(subscriber => {
  50. if(subscriber.key === key) subscriber.func(payload, this.state);
  51. });
  52. };
  53. // event listeners:
  54. addEventListener = (key: string, func: (state: T) => void) => {
  55. this.subscribers.push({
  56. func,
  57. key
  58. });
  59. };
  60. removeEventListener = (key: string) => {
  61. const funcIndex = this.subscribers.findIndex(subscriber => subscriber.key === key);
  62. if(funcIndex > -1) {
  63. this.subscribers.splice(funcIndex, 1);
  64. }
  65. };
  66. removeAllListeners = () => {
  67. this.subscribers = [];
  68. };
  69. // context provider:
  70. Provider = ({
  71. children
  72. }: {
  73. children: ReactNode;
  74. }) => {
  75. const StateContextRenderer = this.stateContext;
  76. const [state, setState]: [T, Dispatch<Partial<T>>] = useReducer((state: T, nextState: Partial<T>) => {
  77. const newState = {
  78. ...state,
  79. ...nextState
  80. };
  81. this.state = newState;
  82. this.emit(undefined, this.state);
  83. if(this.config.isSaveState && this.config.onStorageUpdate) {
  84. this.config.onStorageUpdate(this.state);
  85. }
  86. return newState;
  87. }, this.state);
  88. useEffect(() => {
  89. this.setState = setState;
  90. }, []);
  91. return <StateContextRenderer.Provider
  92. value={state}
  93. >
  94. {children}
  95. </StateContextRenderer.Provider>;
  96. };
  97. };
  98. export default NCoreContext;