moved global state loic to separate file

- moved related types and interfaces too
This commit is contained in:
Kim, Jimin 2022-03-26 17:37:40 +09:00
parent 1e645a14ca
commit 9861aeda7f
4 changed files with 95 additions and 30 deletions

View file

@ -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<ThemeType>(
(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 (
<IENotSupported>
@ -70,9 +59,9 @@ const App = () => {
return (
<ThemeProvider
theme={{
currentTheme: currentTheme,
currentTheme: globalState.theme,
setTheme(setThemeTo) {
setCurrentTheme(setThemeTo)
dispatch({ type: ActionsEnum.UPDATE_THEME, payload: setThemeTo })
},
}}
>
@ -104,5 +93,3 @@ const App = () => {
</ThemeProvider>
)
}
export default App

76
src/globalContext.tsx Normal file
View file

@ -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<GlobalAction>
}
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 (
<globalContext.Provider value={{ globalState, dispatch }}>
{props.children}
</globalContext.Provider>
)
}

View file

@ -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(
<React.StrictMode>
<BrowserRouter>
<HelmetProvider>
<App />
</HelmetProvider>
</BrowserRouter>
<GlobalStore>
<BrowserRouter>
<HelmetProvider>
<App />
</HelmetProvider>
</BrowserRouter>
</GlobalStore>
</React.StrictMode>,
document.getElementById("root")
)

View file

@ -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
}
}