From 9861aeda7fe23363e70997d98d276eb958f61adc Mon Sep 17 00:00:00 2001 From: developomp Date: Sat, 26 Mar 2022 17:37:40 +0900 Subject: [PATCH] moved global state loic to separate file - moved related types and interfaces too --- src/App.tsx | 29 ++++----------- src/globalContext.tsx | 76 ++++++++++++++++++++++++++++++++++++++ src/index.tsx | 13 ++++--- types/styled-components.ts | 7 ++-- 4 files changed, 95 insertions(+), 30 deletions(-) create mode 100644 src/globalContext.tsx diff --git a/src/App.tsx b/src/App.tsx index 866aac2..cc1e76e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,9 @@ -import { useEffect, useState } from "react" +import { useContext, useEffect, useState } from "react" import { Routes, Route } from "react-router-dom" import styled, { ThemeProvider } from "styled-components" import { Helmet } from "react-helmet-async" -import storage from "local-storage-fallback" import { isIE } from "react-device-detect" -import { ThemeType } from "../types/styled-components" - import Loading from "./components/Loading" import Navbar from "./components/Navbar" import Footer from "./components/Footer" @@ -20,6 +17,8 @@ import Portfolio from "./pages/Portfolio" import theming from "./styles/theming" import GlobalStyle from "./styles/globalStyle" +import { ActionsEnum, globalContext } from "./globalContext" + const IENotSupported = styled.p` margin: auto; font-size: 2rem; @@ -34,17 +33,12 @@ const StyledContentContainer = styled.div` margin-top: 5rem; ` -const App = () => { +export default function App() { + const { globalState, dispatch } = useContext(globalContext) const [isLoading, setIsLoading] = useState(true) - const [currentTheme, setCurrentTheme] = useState( - (storage.getItem("theme") || "dark") as ThemeType // get theme from storage and set to "dark" mode if not set already - ) + // set loading to false if all fonts are loaded useEffect(() => { - // show loading screen until all fonts are loaded. - // Experimental feature. Not fully supported on all browsers (IE, I'm looking at you). - // https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet - // checks if document.fonts.onloadingdone is supported on the browser if (typeof document.fonts.onloadingdone != undefined) { document.fonts.onloadingdone = () => { @@ -55,11 +49,6 @@ const App = () => { } }, []) - useEffect(() => { - // save theme when it is changed - storage.setItem("theme", currentTheme) - }, [currentTheme]) - if (isIE) return ( @@ -70,9 +59,9 @@ const App = () => { return ( @@ -104,5 +93,3 @@ const App = () => { ) } - -export default App diff --git a/src/globalContext.tsx b/src/globalContext.tsx new file mode 100644 index 0000000..5814fd8 --- /dev/null +++ b/src/globalContext.tsx @@ -0,0 +1,76 @@ +import { createContext, useEffect, useReducer } from "react" +import storage from "local-storage-fallback" + +import type { Dispatch, ReactNode, ReactElement } from "react" + +export type SiteLocale = "en" | "kr" +export type SiteTheme = "dark" | "light" + +export enum ActionsEnum { + UPDATE_THEME, + UPDATE_LOCALE, +} + +export interface IGlobalState { + locale: SiteLocale + theme: SiteTheme +} + +export type GlobalAction = + | { + type: ActionsEnum.UPDATE_THEME + payload: SiteTheme + } + | { + type: ActionsEnum.UPDATE_LOCALE + payload: SiteLocale + } + +export interface IGlobalContext { + globalState: IGlobalState + dispatch: Dispatch +} + +const defaultState: IGlobalState = { + locale: (storage.getItem("locale") || "en") as SiteLocale, + theme: (storage.getItem("theme") || "dark") as SiteTheme, +} + +export const globalContext = createContext({} as IGlobalContext) + +function reducer(state = defaultState, action: GlobalAction): IGlobalState { + switch (action.type) { + case ActionsEnum.UPDATE_THEME: + state.theme = action.payload + break + + case ActionsEnum.UPDATE_LOCALE: + state.locale = action.payload + break + + default: + break + } + + return { ...state } +} + +export function GlobalStore(props: { children: ReactNode }): ReactElement { + const [globalState, dispatch] = useReducer(reducer, defaultState) + + // save theme when it is changed + useEffect(() => { + storage.setItem("theme", globalState.theme) + }, [globalState.theme]) + + // save locale when it is changed + useEffect(() => { + storage.setItem("locale", globalState.locale) + }, [globalState.locale]) + + return ( + + {props.children} + + ) +} diff --git a/src/index.tsx b/src/index.tsx index 0f5fe58..092e55f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,16 +2,19 @@ import React from "react" import ReactDOM from "react-dom" import { HelmetProvider } from "react-helmet-async" import { BrowserRouter } from "react-router-dom" +import { GlobalStore } from "./globalContext" import App from "./App" ReactDOM.render( - - - - - + + + + + + + , document.getElementById("root") ) diff --git a/types/styled-components.ts b/types/styled-components.ts index 8ad51f8..db2c3e9 100644 --- a/types/styled-components.ts +++ b/types/styled-components.ts @@ -1,10 +1,9 @@ import "styled-components" - -export type ThemeType = "dark" | "light" +import type { SiteTheme } from "../src/globalContext" declare module "styled-components" { export interface DefaultTheme { - currentTheme: ThemeType - setTheme(setThemeTo: ThemeType): void + currentTheme: SiteTheme + setTheme(setThemeTo: SiteTheme): void } }