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 { Routes, Route } from "react-router-dom"
import styled, { ThemeProvider } from "styled-components" import styled, { ThemeProvider } from "styled-components"
import { Helmet } from "react-helmet-async" import { Helmet } from "react-helmet-async"
import storage from "local-storage-fallback"
import { isIE } from "react-device-detect" import { isIE } from "react-device-detect"
import { ThemeType } from "../types/styled-components"
import Loading from "./components/Loading" import Loading from "./components/Loading"
import Navbar from "./components/Navbar" import Navbar from "./components/Navbar"
import Footer from "./components/Footer" import Footer from "./components/Footer"
@ -20,6 +17,8 @@ import Portfolio from "./pages/Portfolio"
import theming from "./styles/theming" import theming from "./styles/theming"
import GlobalStyle from "./styles/globalStyle" import GlobalStyle from "./styles/globalStyle"
import { ActionsEnum, globalContext } from "./globalContext"
const IENotSupported = styled.p` const IENotSupported = styled.p`
margin: auto; margin: auto;
font-size: 2rem; font-size: 2rem;
@ -34,17 +33,12 @@ const StyledContentContainer = styled.div`
margin-top: 5rem; margin-top: 5rem;
` `
const App = () => { export default function App() {
const { globalState, dispatch } = useContext(globalContext)
const [isLoading, setIsLoading] = useState(true) 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(() => { 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 // checks if document.fonts.onloadingdone is supported on the browser
if (typeof document.fonts.onloadingdone != undefined) { if (typeof document.fonts.onloadingdone != undefined) {
document.fonts.onloadingdone = () => { document.fonts.onloadingdone = () => {
@ -55,11 +49,6 @@ const App = () => {
} }
}, []) }, [])
useEffect(() => {
// save theme when it is changed
storage.setItem("theme", currentTheme)
}, [currentTheme])
if (isIE) if (isIE)
return ( return (
<IENotSupported> <IENotSupported>
@ -70,9 +59,9 @@ const App = () => {
return ( return (
<ThemeProvider <ThemeProvider
theme={{ theme={{
currentTheme: currentTheme, currentTheme: globalState.theme,
setTheme(setThemeTo) { setTheme(setThemeTo) {
setCurrentTheme(setThemeTo) dispatch({ type: ActionsEnum.UPDATE_THEME, payload: setThemeTo })
}, },
}} }}
> >
@ -104,5 +93,3 @@ const App = () => {
</ThemeProvider> </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 ReactDOM from "react-dom"
import { HelmetProvider } from "react-helmet-async" import { HelmetProvider } from "react-helmet-async"
import { BrowserRouter } from "react-router-dom" import { BrowserRouter } from "react-router-dom"
import { GlobalStore } from "./globalContext"
import App from "./App" import App from "./App"
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<BrowserRouter> <GlobalStore>
<HelmetProvider> <BrowserRouter>
<App /> <HelmetProvider>
</HelmetProvider> <App />
</BrowserRouter> </HelmetProvider>
</BrowserRouter>
</GlobalStore>
</React.StrictMode>, </React.StrictMode>,
document.getElementById("root") document.getElementById("root")
) )

View file

@ -1,10 +1,9 @@
import "styled-components" import "styled-components"
import type { SiteTheme } from "../src/globalContext"
export type ThemeType = "dark" | "light"
declare module "styled-components" { declare module "styled-components" {
export interface DefaultTheme { export interface DefaultTheme {
currentTheme: ThemeType currentTheme: SiteTheme
setTheme(setThemeTo: ThemeType): void setTheme(setThemeTo: SiteTheme): void
} }
} }