wrong Initial state in zustand in nextjs server side - reactjs

I use zustand as a global state manager and I want use of the persisted states in server side of nextjs pages. but when I log the currently state values it will print default values (which the default values are null) and it does not log the updated states values.
The codes are here:
store.ts
/**
*? For more information about config zustand store in nextjs visit here:
*? https://github.com/vercel/next.js/blob/canary/examples/with-zustand/lib/store.js
*/
import { useLayoutEffect } from 'react';
import create, { StoreApi } from 'zustand';
import createContext from 'zustand/context';
import { devtools, persist, PersistOptions } from 'zustand/middleware';
import { createClinicSlice } from './slices/clinic';
import { createUserSlice } from './slices/user';
import type { IClinicSlice, IResetState, IUserSlice } from '$types';
const persistProperties: PersistOptions<any> = {
name: 'globalStorage',
getStorage: () => localStorage,
// ? should update version when app version updated
version: 0,
};
let store: any;
interface IInitialState {
clinics: null;
activeClinic: null;
user: null;
}
const getDefaultInitialState = (): IInitialState => ({
clinics: null,
activeClinic: null,
user: null,
});
const zustandContext = createContext<StoreApi<IClinicSlice & IUserSlice & IResetState>>();
export const Provider = zustandContext.Provider;
export const useStore = zustandContext.useStore;
export const initializeStore = (preloadedState: Record<string, any> = {}) => {
return create<IClinicSlice & IUserSlice & IResetState>()(
devtools(
persist(
(set) => ({
...getDefaultInitialState(),
...preloadedState,
// #ts-ignore
...createClinicSlice(set),
// #ts-ignore
...createUserSlice(set),
resetStore: () => set(getDefaultInitialState()),
}),
persistProperties
)
)
);
};
export function useCreateStore(
serverInitialState: Record<string, any>
): typeof initializeStore {
if (typeof window === 'undefined') {
return () => initializeStore(serverInitialState);
}
const isReusingStore = Boolean(store);
store = store ?? initializeStore(serverInitialState);
useLayoutEffect(() => {
// serverInitialState is undefined for CSR pages. It is up to you if you want to reset
// states on CSR page navigation or not. I have chosen not to, but if you choose to,
// then add `serverInitialState = getDefaultInitialState()` here.
if (serverInitialState && isReusingStore) {
store.setState(
{
// re-use functions from existing store
...store.getState(),
// but reset all other properties.
...(serverInitialState || getDefaultInitialState()),
},
true // replace states, rather than shallow merging
);
}
});
return () => store;
}
_app.tsx
import { useEffect } from 'react';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider, jssPreset, StylesProvider } from '#material-ui/core/styles';
import i18n from 'i18next';
import { create } from 'jss';
import rtl from 'jss-rtl';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import { I18nextProvider } from 'react-i18next';
import { ThemeProvider as SCThemeProvider } from 'styled-components';
import muiTheme from '$/assets/style/theme';
import { AuthProvider } from '$/components/contexts/auth';
import { ReactToastify } from '$/components/ReactToastify/ReactToastify';
import { Provider, useCreateStore } from '$store';
import '../../public/assets/style/index.css';
import 'leaflet/dist/leaflet.css';
import 'leaflet-geosearch/assets/css/leaflet.css';
import 'leaflet-geosearch/dist/geosearch.css';
import 'react-toastify/dist/ReactToastify.css';
import '$/utils/i18n.config';
const jss = create({
plugins: [...jssPreset().plugins, rtl()],
});
function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentElement!.removeChild(jssStyles);
}
}, []);
const createStore = useCreateStore(pageProps.initialZustandState);
return (
<>
<Head>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
/>
</Head>
<Provider createStore={createStore}>
<I18nextProvider i18n={i18n}>
<ReactToastify />
</I18nextProvider>
<StylesProvider jss={jss}>
<ThemeProvider theme={muiTheme}>
<SCThemeProvider theme={muiTheme}>
<CssBaseline />
<AuthProvider>
<I18nextProvider i18n={i18n}>
<Component {...pageProps} />
</I18nextProvider>
</AuthProvider>
</SCThemeProvider>
</ThemeProvider>
</StylesProvider>
</Provider>
</>
);
}
export default MyApp;
dashboard/index.tsx
import { useEffect } from 'react';
import type { NextPage } from 'next';
import { useRouter } from 'next/router';
import { PageScrollableArea } from '$/components/index';
import ClinicDashboardLayout from '$/components/layout/clinicDashboardLayout/ClinicDashboardLayout';
import { isNil } from '$/utils/stringUtils';
import ClinicDashboard from '$/view/clinic/Dashboard';
import withPrivateRoute from '$/view/hocs/withPrivateRoute';
import { CLINICS_PAGE_URL } from '$constant';
import { initializeStore, useStore } from '$store';
const Dashboard: NextPage = (props) => {
return (
<ClinicDashboardLayout>
<PageScrollableArea>
<ClinicDashboard />
</PageScrollableArea>
</ClinicDashboardLayout>
);
};
export default withPrivateRoute(Dashboard);
export function getServerSideProps() {
const zustandStore = initializeStore();
console.log(`===> zustandStore.getState() ===>`, zustandStore.getState());
// if (isNil(zustandStore.getState().activeClinic)) {
// return {
// redirect: {
// destination: CLINICS_PAGE_URL,
// permanent: true,
// },
// };
// }
return {
props: {},
};
}
I find out the store variable in store.ts file always is undefined and its value will not update as values are located in local storage
Does anybody have a similar experience with this issue?

Related

After building nextjs app, chunk/pages/_app-.....js file size is too large

I have a next js project that is created by create next app and modified _app.ts to this
import "../../public/assets/css/bootstrap.css";
import "antd/dist/antd.css";
import "../../public/assets/css/common.css";
import "../styles/globals.css";
import "../styles/builderGlobals.css";
import "../../public/assets/css/quiz.css";
import "../../public/assets/css/main.css";
import "../../public/assets/css/responsive.css";
import Head from "next/head";
import { wrapper } from "../app/store";
import { setUser } from "../Modules/Auth/authSlice";
import Layout from "../components/Layouts/layout";
import type { AppPropsWithLayout } from "../utils/types";
import { setNotifSettingsData } from "../Modules/Notifications/notificationsSlice";
import serverApi from "../utils/axios/serverApi";
import NextNProgress from "nextjs-progressbar";
import { useAppSelector } from "../app/hooks";
const MyApp = ({ Component, pageProps }: AppPropsWithLayout) => {
const favicon = useAppSelector(state => state.settingsData.favico_icon);
const getLayout =
Component.getLayout ??
((page) => (
<Layout>
<Head>
<link rel="shortcut icon" href={favicon || "/img/favicon.png"} />
</Head>
<NextNProgress /> {page}
</Layout>
));
return getLayout(<Component {...pageProps} />);
};
MyApp.getInitialProps = wrapper.getInitialAppProps(
(store) =>
async ({ Component, ctx }) => {
if (!ctx.req) {
return {
pageProps: {
...(Component.getInitialProps
? await Component.getInitialProps({ ...ctx, store })
: {}),
pathname: ctx.pathname,
},
};
}
try {
const { data: initialData } = await serverApi(
ctx,
`/settings/get-initial-site-data`
);
store.dispatch(setUser(initialData?.authUser));
store.dispatch(setNotifSettingsData(initialData?.siteSettings));
return {
pageProps: {
...(Component.getInitialProps
? await Component.getInitialProps({ ...ctx, store })
: {}),
pathname: ctx.pathname,
},
};
} catch (error) {
ctx.res.statusCode = 404;
ctx.res.end("Not found");
return;
}
}
);
export default wrapper.withRedux(MyApp);
But after running yarn build it created too large _app chunk. about 431kb
That is huge. How can I reduce this chunk? or am I doing anything wrong?
https://github.com/sakib412/sakib412/raw/main/WhatsApp%20Image%202022-10-13%20at%206.48.08%20PM.jpeg

Mocked dispatch being fired but state not changing

I think i'm misunderstanding some concept about jest functions, I'm trying to test if after a click my isCartOpen is being set to true; the function is working, being called with the desired value.
The problem is that my state isn't changing at all. I tried to set a spy to dispatch but i really can't understand how spy works or if it's even necessary in this case
// cart-icons.test.tsx
import { render, screen, fireEvent } from 'utils/test'
import CartIcon from './cart-icon.component'
import store from 'app/store'
import { setIsCartOpen } from 'features/cart/cart.slice'
const mockDispatchFn = jest.fn()
jest.mock('hooks/redux', () => ({
...jest.requireActual('hooks/redux'),
useAppDispatch: () => mockDispatchFn,
}))
describe('[Component] CartIcon', () => {
beforeEach(() => render(<CartIcon />))
it('Dispatch open/close cart action when clicked', async () => {
const { isCartOpen } = store.getState().cart
const iconContainer = screen.getByText(/shopping-bag.svg/i)
.parentElement as HTMLElement
expect(isCartOpen).toBe(false)
fireEvent.click(iconContainer)
expect(mockDispatchFn).toHaveBeenCalledWith(setIsCartOpen(true))
// THIS SHOULD BE WORKING, BUT STATE ISN'T CHANGING!
expect(isCartOpen).toBe(true)
})
})
// cart-icon.component.tsx
import { useAppDispatch, useAppSelector } from 'hooks/redux'
import { selectIsCartOpen, selectCartCount } from 'features/cart/cart.selector'
import { setIsCartOpen } from 'features/cart/cart.slice'
import { ShoppingIcon, CartIconContainer, ItemCount } from './cart-icon.styles'
const CartIcon = () => {
const dispatch = useAppDispatch()
const isCartOpen = useAppSelector(selectIsCartOpen)
const cartCount = useAppSelector(selectCartCount)
const toggleIsCartOpen = () => dispatch(setIsCartOpen(!isCartOpen))
return (
<CartIconContainer onClick={toggleIsCartOpen}>
<ShoppingIcon />
<ItemCount>{cartCount}</ItemCount>
</CartIconContainer>
)
}
export default CartIcon
// utils/test.tsx
import React, { FC, ReactElement } from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import { ApolloProvider } from '#apollo/client'
import { Elements } from '#stripe/react-stripe-js'
import { render, RenderOptions } from '#testing-library/react'
import store from 'app/store'
import { apolloClient, injectStore } from 'app/api'
import { stripePromise } from './stripe/stripe.utils'
injectStore(store)
const AllTheProviders: FC<{ children: React.ReactNode }> = ({ children }) => {
return (
<Provider store={store}>
<ApolloProvider client={apolloClient}>
<BrowserRouter>
<Elements stripe={stripePromise}>{children}</Elements>
</BrowserRouter>
</ApolloProvider>
</Provider>
)
}
const customRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>
) => render(ui, { wrapper: AllTheProviders, ...options })
export * from '#testing-library/react'
export { customRender as render }

Data is losing during page refresh in Reactjs-Redux; Tried using 'redux-persist' and localstorage , but not working

In our project,forms(login,signup,logout,etc..) were built in django and through this we are getting the authorization details and this was stored as redux-data and was used in the rest of the application which is built in react.There was no refresh issue during that time.evenif the store was getting disapper but we are getting it back.Now,we shifted all that we done in Django into react and used the same redux storage method in login,but we are facing the data losage during refresh,store is not getting restore and we are having 403 status for 2 apis for getting the user details.This was not happening in former case.
We used redux-persist package to avoid this data losage.. And also tried using localstorage persisting method(loadState(),saveState()).But,still facing the issue.
store.js
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: "root",
storage,
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const persistedReducer = persistReducer(persistConfig,rootReducer)
const store = createStore(persistedReducer,composeEnhancers(applyMiddleware(thunk)))
const Persistor = persistStore(store);
export default (store)
export { Persistor }
action.js:
import axios from 'axios'
import { SET_PROFILE, SET_FEATURE_TOGGLES } from './actionTypes'
import { client_request_data } from '../config';
const redirectToLogin = () => {
delete axios.defaults.headers.common.Authorization
if (window.location.href.indexOf('/accounts/') !== -1) {
window.location.href = '/accounts/login'
}
}
export const fetchUserProfile = () => dispatch => {
axios
.post(`/accounts/user_profile/`,{
client_request_data: client_request_data
})
.then(resp =>
dispatch({
type: SET_PROFILE,
payload: resp.data,
}),
)
.catch(e => {
// TODO figure out what do do here
if (e.response?.status === 403) {
redirectToLogin()
}
})
}
export const fetchFeatureToggles = () => dispatch => {
axios
.post(`/api/study/v1/feature_toggle/`,{
client_request_data: client_request_data
})
.then(resp =>
dispatch({
type: SET_FEATURE_TOGGLES,
payload: resp.data,
}),
)
.catch(e => {
// TODO figure out what do do here
if (e.response?.status === 403) {
redirectToLogin()
}
})
}
Reducers:1.featureToggle.js
import { SET_FEATURE_TOGGLES } from '../actionTypes'
const intialstate = {}
export default (state = intialstate, action) => {
switch (action.type) {
case SET_FEATURE_TOGGLES:
return action.payload
default:
return state
}
}
2.userprofile.js
import { SET_PROFILE } from '../actionTypes'
const intialstate = {}
export default (state = {}, action) => {
switch (action.type) {
case SET_PROFILE:
return action.payload
default:
return state
}
}
App.js:
import React, { useEffect, Suspense } from 'react'
import { connect } from 'react-redux'
import CssBaseline from '#material-ui/core/CssBaseline'
import { ThemeProvider } from '#material-ui/styles'
import MuiThemeProvider from '#material-ui/core/styles/MuiThemeProvider'
import { Provider } from 'react-redux'
import { BrowserRouter, Switch, Route } from 'react-router-dom'
import theme from './theme/muiTheme'
import './i18n'
import Home from './screens/Home'
import * as actions from './redux/actions'
import Userservice from './services/UserService'
import { BASE_URL} from './config'
import Login from './Login'
import Signup from './Signup'
import Logout from './Logout'
import ResetPassword from './ResetPassword'
import ResetSuccess from './ResetSuccess'
import store from './redux/store'
const App = props => {
const {
userProfile,
featureToggles,
fetchUserProfile,
fetchFeatureToggles,
} = props
useEffect(() => {
fetchUserProfile()
fetchFeatureToggles()
})
return (
<Suspense fallback={<span></span>}>
<BrowserRouter>
<Switch>
<Route
exact
path="/"
render={() => {
return (
userProfile === null || featureToggles === null ? <Login/> : <Home />
)
}}
/>
</Switch>
</BrowserRouter>
</Suspense>
)
}
const mapStateToProps = state => ({
userProfile: state.userProfile,
featureToggles: state.featureToggles,
})
export default connect(mapStateToProps, actions)(App)
index.js:
import promiseFinally from 'promise.prototype.finally'
import React, {Suspense} from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import CssBaseline from '#material-ui/core/CssBaseline'
import { ThemeProvider } from '#material-ui/styles'
import MuiThemeProvider from '#material-ui/core/styles/MuiThemeProvider'
import { Provider } from 'react-redux'
import * as serviceWorker from './serviceWorker'
import App from './App'
import theme from './theme/muiTheme'
import store,{Persistor} from './redux/store'
import './i18n';
import Home from './screens/Home'
import Login from './Login'
import Signup from './Signup'
import Logout from './Logout'
import { PersistGate } from 'redux-persist/integration/react'
promiseFinally.shim()
ReactDOM.render(
<Provider store={store}>
<PersistGate Loading={null} persistor={Persistor}>
<MuiThemeProvider theme={theme}>
<ThemeProvider theme={theme}>
<CssBaseline />
<Suspense>
<App />
</Suspense>
</ThemeProvider>
</MuiThemeProvider>
</PersistGate>
</Provider>,
document.getElementById('root'),
)
serviceWorker.unregister()
Also tried with localstorage: localstorage.js(in redux)
export const loadState = () => {
try {
const serializedState = localStorage.getItem("state");
if (serializedState === null) {
return undefined;
}
return JSON.parse(serializedState);
} catch (err) {
return undefined;
}
};
export const saveState = (state) => {
try {
const serializesState = JSON.stringify(state);
localStorage.setItem("state", serializesState);
} catch (err) {
console.log(err);
}
};
Corresponding store.js:
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers'
import { persistStore,persistReducer} from 'redux-persist'
import storage from 'redux-persist/lib/storage';
import { fetchFeatureToggles } from './actions';
import { loadState,saveState } from './localStorage';
import { throttle } from 'lodash';
const persistConfig = {
key: "root",
storage,
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const persistedState = loadState();
const persistedReducer = persistReducer(persistConfig,rootReducer)
const store = createStore(persistedReducer,persistedState,composeEnhancers(applyMiddleware(thunk)))
store.subscribe(throttle(() => {
saveState(store.getState());
},1000));
const Persistor = persistStore(store);
export default store
export {Persistor}

Next JS code inside getInitialProps not executes after page reload

I'm integrating NextJS into my React app. I face a problem, on page reload or opening direct link(ex. somehostname.com/clients) my getInitialProps not executes, but if I open this page using <Link> from next/link it works well. I don't really understand why it happens and how to fix it. I have already came throught similar questions, but didn't find any solution which could be suitable for me.
Clients page code:
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { ClientsTable } from '../../src/components/ui/tables/client-table';
import AddIcon from '#material-ui/icons/Add';
import Fab from '#material-ui/core/Fab';
import { AddClientModal } from '../../src/components/ui/modals/add-client-modal';
import CircularProgress from '#material-ui/core/CircularProgress';
import { Alert } from '../../src/components/ui/alert';
import { Color } from '#material-ui/lab/Alert';
import { AppState } from '../../src/store/types';
import { thunkAddClient, thunkGetClients } from '../../src/store/thunks/clients';
import { SnackbarOrigin } from '#material-ui/core';
import { IClientsState } from '../../src/store/reducers/clients';
import { NextPage } from 'next';
import { ReduxNextPageContext } from '../index';
import { PageLayout } from '../../src/components/ui/page-layout';
const Clients: NextPage = () => {
const [addClientModalOpened, setAddClientModalOpened] = useState<boolean>(false);
const [alertType, setAlertType] = useState<Color>('error');
const [showAlert, setAlertShow] = useState<boolean>(false);
const alertOrigin: SnackbarOrigin = { vertical: 'top', horizontal: 'center' };
const dispatch = useDispatch();
const { clients, isLoading, hasError, message, success } = useSelector<AppState, IClientsState>(state => state.clients);
useEffect(() => {
if (success) {
handleAddModalClose();
}
}, [success]);
useEffect(() => {
checkAlert();
}, [hasError, success, isLoading]);
function handleAddModalClose(): void {
setAddClientModalOpened(false);
}
function handleAddClient(newClientName: string): void {
dispatch(thunkAddClient(newClientName));
}
function checkAlert() {
if (!isLoading && hasError) {
setAlertType('error');
setAlertShow(true);
} else if (!isLoading && success) {
setAlertType('success');
setAlertShow(true);
} else {
setAlertShow(false);
}
}
return (
<PageLayout>
<div className='clients'>
<h1>Clients</h1>
<div className='clients__add'>
<div className='clients__add-text'>
Add client
</div>
<Fab color='primary' aria-label='add' size='medium' onClick={() => setAddClientModalOpened(true)}>
<AddIcon/>
</Fab>
<AddClientModal
opened={addClientModalOpened}
handleClose={handleAddModalClose}
handleAddClient={handleAddClient}
error={message}
/>
</div>
<Alert
open={showAlert}
message={message}
type={alertType}
origin={alertOrigin}
autoHideDuration={success ? 2500 : null}
/>
{isLoading && <CircularProgress/>}
{!isLoading && <ClientsTable clients={clients}/>}
</div>
</PageLayout>
);
};
Clients.getInitialProps = async ({ store }: ReduxNextPageContext) => {
await store.dispatch(thunkGetClients());
return {};
};
export default Clients;
thunkGetClients()
export function thunkGetClients(): AppThunk {
return async function(dispatch) {
const reqPayload: IFetchParams = {
method: 'GET',
url: '/clients'
};
try {
dispatch(requestAction());
const { clients } = await fetchData(reqPayload);
console.log(clients);
dispatch(getClientsSuccessAction(clients));
} catch (error) {
dispatch(requestFailedAction(error.message));
}
};
}
_app.tsx code
import React from 'react';
import App, { AppContext, AppInitialProps } from 'next/app';
import withRedux from 'next-redux-wrapper';
import { Provider } from 'react-redux';
import { makeStore } from '../../src/store';
import { Store } from 'redux';
import '../../src/sass/app.scss';
import { ThunkDispatch } from 'redux-thunk';
export interface AppStore extends Store {
dispatch: ThunkDispatch<any, any, any>;
}
export interface MyAppProps extends AppInitialProps {
store: AppStore;
}
export default withRedux(makeStore)(
class MyApp extends App<MyAppProps> {
static async getInitialProps({
Component,
ctx
}: AppContext): Promise<AppInitialProps> {
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</>
);
}
}
);
Looking for your advices and help. Unfortunately, I couldn't find solution by myself.
This is the way Next.js works, it runs getInitialProps on first page load (reload or external link) in the server, and rest of pages that where navigated to with Link it will run this method on client.
The reason for this is to allow Next.js sites to have "native" SEO version.

React TypeScript: How to userReducer with two different contexts?

On the Home page, I want to be able to change the language, to 'kr' from the default 'en'. I've made the button click call a function and I then change the context which in turn calls the reducer, is this the right way?
Also when I use the reducer am I mutating the state or not?
How do I apply types to the action in the reducer and the default state?
import React, { useReducer } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { setGlobalContext, globalContext } from "./components/context";
import { Layout } from "./components/layout";
import { Home } from './routes/home';
import { NotFound } from './routes/not-found';
import { globalReducer } from './components/reducer'
const Router: React.FC = () => {
const [global, setGlobal] = useReducer(globalReducer, {
language: 'en',
})
return (
<setGlobalContext.Provider value={{ setGlobal }}>
<globalContext.Provider value={{ global }}>
<BrowserRouter>
<Route render={({ location }) => (
<Layout location={ location }>
<Switch location={ location }>
<Route exact path = '/' component = { Home } />
<Route component = { NotFound }/>
</Switch>
</Layout>
)} />
</BrowserRouter>
</globalContext.Provider>
</setGlobalContext.Provider>
);
}
export { Router };
./components/reducer looks like
const CHANGE_LANGUAGE = 'CHANGE_LANGUAGE';
const globalReducer = (state: any, action: any) => {
switch (action.type) {
case CHANGE_LANGUAGE:
return {...state,
language: action.value
}
default:
return state
}
}
export { globalReducer, CHANGE_LANGUAGE }
and ./components/context
import React from "react";
const setGlobalContext = React.createContext({});
const globalContext = React.createContext({});
export { setGlobalContext, globalContext };
and ./routes/home
import React, { useContext, useEffect, useRef, useState} from 'react';
import { setGlobalContext, globalContext } from "./context";
import { CHANGE_LANGUAGE } from './components/reducer'
const Home: React.FC<propsInterface> = (props) => {
const { global } = useContext(globalContext) as {global: any};
const { setGlobal } = useContext(setGlobalContext) as {setGlobal: React.Dispatch<React.SetStateAction<any>>};
const changeLanguage = () => {
setGlobal({type: CHANGE_LANGUAGE, value: 'kr'})
}
return (
<button onClick={changeLanguage}>Change language to Korean<button>
)
}
export { Home };

Resources