-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathglobal-state.tsx
94 lines (80 loc) · 2.85 KB
/
global-state.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
* Author: Jesper Sporron
* Author GitHub: https://github.com/Charanor
* Project Github: https://github.com/Charanor/react-native-code-snippets
* License: Creative Commons Zero v1.0 Universal (CC0)
*
* Description:
* This is a module that allows your app to have a global state without using Redux. You can interract with
* the global state using hooks or a context consumer.
*
* Please keep this comment at the top of the file to show support (even though you are free to remove it) :)
*/
import React, { createContext, useReducer, useContext } from "react";
//////////////////////////////////////////////////
/// These are the only things you need to edit ///
//////////////////////////////////////////////////
// This is your initial state. The exported type is automatically determined from this.
const INITIAL_STATE = {
data: ""
};
type GlobalStateType = typeof INITIAL_STATE;
// Change this to match your actions. "type" should be present on all actions.
type ExampleAction = { type: "EXAMPLE", data: string };
type Action = ExampleAction;
function reducer(state: GlobalStateType, action: Action): GlobalStateType {
let newState: GlobalStateType = null;
switch (action.type) {
case "EXAMPLE": {
const { data } = action;
newState = { ...state, data }; // Do this for every action.
break;
}
default:
// Note: This should NEVER happen but because JS is dynamic and
// still compiles when TS has syntax errors it can...
throw new Error(`GlobalState cannot handle action ${action}`);
}
listeners.forEach(listener => listener(newState));
return newState;
}
///////////////////////////////////////
/// Static stuff, no need to change ///
///////////////////////////////////////
type DispatchFunc = (action: Action) => void;
type GlobalStateProviderType = {
state: GlobalStateType,
dispatch: DispatchFunc;
}
type StateListener = (state: GlobalStateType) => void;
const GlobalStateContext = createContext<GlobalStateProviderType>(null);
const listeners: StateListener[] = [];
function GlobalStateProvider({ children }) {
const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
return (
<GlobalStateContext.Provider value={{ state, dispatch }}>
{children}
</GlobalStateContext.Provider>
);
}
function addListener(listener: StateListener) {
listeners.push(listener);
return () => {
// Must calculate here, can't use return value from 'push'
const idx = listeners.indexOf(listener);
if (idx >= 0) listeners.splice(idx, 1);
};
}
function useGlobalState() {
return useContext(GlobalStateContext);
}
export {
GlobalStateProvider,
GlobalStateContext,
GlobalStateProviderType,
GlobalStateType,
DispatchFunc,
Action,
addListener,
useGlobalState
};