diff --git a/.gitignore b/.gitignore
index 52326e42..41f14643 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,5 @@ coverage/
package-lock.json
ios/Pods/
+
+.vscode
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..87301988
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,32 @@
+{
+ //eslint extension options
+ "eslint.enable": true,
+ "eslint.validate": [
+ "javascript",
+ "javascriptreact",
+ "typescript",
+ "typescriptreact"
+ ],
+
+ // prettier extension setting
+ "editor.formatOnSave": true,
+ "[javascript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "[javascriptreact]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "[typescript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "[typescriptreact]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "prettier.singleQuote": true,
+ "prettier.trailingComma": "all",
+ "prettier.arrowParens": "always",
+ "prettier.jsxSingleQuote": true,
+ // relative path is preferred
+ "javascript.preferences.importModuleSpecifier": "relative",
+ "typescript.preferences.importModuleSpecifier": "relative"
+}
diff --git a/src/App.tsx b/src/App.tsx
index 589efd30..99c8b1ae 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,12 +1,15 @@
-import { AppProvider as Provider } from './providers';
+import { AppProvider } from './providers';
import React from 'react';
import SwitchNavigator from './components/navigation/SwitchNavigator';
+import { ThemeProvider } from 'providers/ThemeProvider';
function App(): React.ReactElement {
return (
-
-
-
+
+
+
+
+
);
}
diff --git a/src/components/navigation/SwitchNavigator.tsx b/src/components/navigation/SwitchNavigator.tsx
index ae115392..1329e00f 100644
--- a/src/components/navigation/SwitchNavigator.tsx
+++ b/src/components/navigation/SwitchNavigator.tsx
@@ -1,10 +1,9 @@
-import React, { useContext } from 'react';
-import { Theme, createTheme } from '../../theme';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
-import { AppContext } from '../../contexts';
+import React from 'react';
import RootNavigator from './RootStackNavigator';
-import { ThemeProvider } from 'styled-components';
+import { Theme } from '../../theme';
+import { useThemeProvicer } from 'providers/ThemeProvider';
const SwitchNavigator = createSwitchNavigator(
{
@@ -22,12 +21,6 @@ export interface ScreenProps {
}
export default function Navigator(): React.ReactElement {
- const { state } = useContext(AppContext);
- const { theme } = state;
-
- return (
-
-
-
- );
+ const { theme } = useThemeProvicer();
+ return ;
}
diff --git a/src/contexts/index.ts b/src/contexts/index.ts
index 3eb4b0b0..6ed986e6 100644
--- a/src/contexts/index.ts
+++ b/src/contexts/index.ts
@@ -1,3 +1 @@
import * as React from 'react';
-
-export const AppContext = React.createContext(null);
diff --git a/src/providers/AppProvider.tsx b/src/providers/AppProvider.tsx
index 3f0aa5fc..f71f8c40 100644
--- a/src/providers/AppProvider.tsx
+++ b/src/providers/AppProvider.tsx
@@ -1,34 +1,22 @@
import React, { useReducer } from 'react';
-import { AppContext } from '../contexts';
-import { ThemeType } from '../theme';
import { User } from '../types';
+import createCtx from 'utils/createCtx';
-const AppConsumer = AppContext.Consumer;
-
-interface Action {
- type: 'reset-user' | 'set-user' | 'change-theme-mode';
- payload: {
- theme: ThemeType;
- user: {
- displayName: string;
- age: number;
- job: string;
- };
- };
+interface Context {
+ state: State;
+ setUser: (user: User) => void;
+ resetUser: () => void;
}
+const [useCtx, Provider] = createCtx();
-interface Props {
- children?: React.ReactElement;
-}
+type dispatchType = 'reset-user' | 'set-user';
export interface State {
user: User;
- theme: ThemeType;
}
const initialState: State = {
- theme: ThemeType.LIGHT,
user: {
displayName: '',
age: 0,
@@ -36,25 +24,50 @@ const initialState: State = {
},
};
-const reducer = (state: State, action: Action): State => {
- // prettier-ignore
+interface Action {
+ type: dispatchType;
+ payload: State;
+}
+
+interface Props {
+ children?: React.ReactElement;
+}
+
+type Reducer = (state: State, action: Action) => State;
+
+const setUser = (dispatch: React.Dispatch) => (user: User) => {
+ dispatch({
+ type: 'set-user',
+ payload: { user },
+ });
+};
+
+const resetUser = (dispatch: React.Dispatch) => () => {
+ dispatch({
+ type: 'reset-user',
+ payload: initialState,
+ });
+};
+
+const reducer: Reducer = (state = initialState, action) => {
switch (action.type) {
- case 'change-theme-mode':
- return { ...state, theme: action.payload.theme };
- case 'reset-user':
- return { ...state, user: initialState.user };
- case 'set-user':
- return { ...state, user: action.payload.user };
+ case 'reset-user':
+ case 'set-user':
+ return { ...state, user: action.payload.user };
+ default:
+ return state;
}
};
function AppProvider(props: Props): React.ReactElement {
- const [state, dispatch] = useReducer(reducer, initialState);
- const value = { state, dispatch };
+ const [state, dispatch] = useReducer(reducer, initialState);
+
+ const actions = {
+ setUser: setUser(dispatch),
+ resetUser: resetUser(dispatch),
+ };
- return (
- {props.children}
- );
+ return {props.children};
}
-export { AppConsumer, AppProvider, AppContext };
+export { useCtx as useAppContext, AppProvider };
diff --git a/src/providers/ThemeProvider.tsx b/src/providers/ThemeProvider.tsx
new file mode 100644
index 00000000..bbce275a
--- /dev/null
+++ b/src/providers/ThemeProvider.tsx
@@ -0,0 +1,38 @@
+import React, { useState } from 'react';
+import { Theme, ThemeType, createTheme } from 'theme';
+
+import { ThemeProvider as OriginalThemeProvider } from 'styled-components';
+import createCtx from 'utils/createCtx';
+
+interface Context {
+ theme: Theme;
+ themeType: ThemeType;
+ changeTheme: React.Dispatch>;
+}
+const [useCtx, Provider] = createCtx();
+
+const initialThemeType: ThemeType = ThemeType.LIGHT;
+
+interface Props {
+ children?: React.ReactElement;
+}
+
+function ThemeProvider(props: Props): React.ReactElement {
+ const [themeType, changeTheme] = useState(initialThemeType);
+ const theme = createTheme(themeType);
+ return (
+
+
+ {props.children}
+
+
+ );
+}
+
+export { useCtx as useThemeProvicer, ThemeProvider };
diff --git a/src/utils/createCtx.ts b/src/utils/createCtx.ts
new file mode 100644
index 00000000..574d5179
--- /dev/null
+++ b/src/utils/createCtx.ts
@@ -0,0 +1,18 @@
+import React from 'react';
+
+// create context with no upfront defaultValue
+// without having to do undefined check all the time
+// prettier-ignore
+function createCtx(): readonly [
+ () => A,
+ React.ProviderExoticComponent>,
+ ] {
+ const ctx = React.createContext(undefined);
+ function useCtx(): A {
+ const c = React.useContext(ctx);
+ if (!c) throw new Error('useCtx must be inside a Provider with a value');
+ return c;
+ }
+ return [useCtx, ctx.Provider] as const; // make TypeScript infer a tuple, not an array of union types
+}
+export default createCtx;