I’ve encountered an issue with determining the device type (mobile, tablet, or desktop) in my Next.js application. I’ve utilized the is-mobile npm package to identify the device type and passing this data through settings. However, the isMobile flag fails to update correctly when I resize the browser window using Chrome’s responsive mode. Even when switching to mobile view, it remains false.
The implementation spans across 3 different files:
In useSetting.ts: I’m deconstructing the settings as shown in the code snippet below:
import useStore from '~/hooks/useStore';
export const useSettings = () => {
const [{ settings }] = useStore();
return settings;
};
The settings are retrieved via useStore.ts. In useStore.ts:
import type { Action } from 'react-sweet-state';
import { createHook, createStore } from 'react-sweet-state';
interface iStates {
settings: iSettings;
}
const actions = {
setSettings: (settings: Record<any, any>): Action<iStates> => {
return ({ setState }) => {
setState({ settings });
};
},
};
const store = createStore<iStates, typeof actions>({
initialState: {
settings: {},
},
actions,
});
export default createHook(store);
During the settings initialization, a warning is generated: Type '{}' is missing the following properties from type 'iSettings': isMobile, isPhone, isTablet, isDesktop, and 3 more.
The interface of iSettings is:
interface iSettings {
isMobile: boolean;
isPhone: boolean;
isTablet: boolean;
isDesktop: boolean;
menu: {
primary: iPrimaryMenuItem[];
footer: iPrimaryMenuItem[];
socials: Array<{ url: string }>;
};
lastUpdate: string;
contactEmails: iContactEmails['emails'];
}
When setting the state in actions, another warning arises:
Type 'Record<any, any>' is missing the following properties from type 'iSettings': isMobile, isPhone, isTablet, isDesktop, and 3 more.
Next, in _app.tsx: I update the settings in the useEffect hook and then pass the settings to the Header file.
import type { NextPageContext } from 'next';
import type { AppProps } from 'next/app';
import { useEffect } from 'react';
import { PagesProgressBar as ProgressBar } from 'next-nprogress-bar';
import { MantineProvider } from '@mantine/core';
import { APIProvider } from '@vis.gl/react-google-maps';
import { useIsBusiness } from '~/hooks';
import useStore from '~/hooks/useStore';
import { getPrimaryMenu, rawFetch } from '~/utilities';
import clsx from 'clsx';
import md from 'is-mobile';
import { Toaster } from 'react-hot-toast';
import '../assets/css/style.css';
App.getInitialProps = async (ctx: NextPageContext) => {
const ua = ctx.req?.headers?.['user-agent'];
const isMobile = md({ ua, tablet: true });
const isPhone = md({ ua });
const isTablet = isMobile && !isPhone;
const isDesktop = !isMobile;
const primaryMenu: iMenu = await rawFetch('/menus/v1/menus/primary');
const socialsMenu: iMenu = await rawFetch('/menus/v1/menus/socials');
const footerMenu: iMenu = await rawFetch('/menus/v1/menus/footer');
const contactEmails: iContactEmails = await rawFetch('/acf/v3/options/options/emails');
const pages = await rawFetch('/wp/v2/pages', { params: { per_page: 1 } });
return {
settings: {
isMobile,
isPhone,
isTablet,
isDesktop,
menu: {
primary: getPrimaryMenu(primaryMenu),
footer: getPrimaryMenu(footerMenu),
socials: socialsMenu.items?.map(({ url }) => ({ url })),
},
lastUpdate: pages?.[0]?.modified,
contactEmails: contactEmails?.emails,
},
};
};
export default function App({ Component, pageProps, settings }: AppProps) {
const [, { setSettings }] = useStore();
const isBusiness = useIsBusiness();
useEffect(() => {
setSettings(settings);
}, []);
return (
<APIProvider apiKey="AIzaSyDoOlmYovBjVqFi9lZKcuOt0xMSEb15OYc">
<div className={clsx(isBusiness && 'dark')}>
<div className="dark:bg-gray-900">
<MantineProvider>
<Component {...pageProps} />
</MantineProvider>
<ProgressBar height="4px" color="rgb(230 178 0)" options={{ showSpinner: false }} shallowRouting />
<Toaster position="top-right" toastOptions={{ style: { borderRadius: '0', background: '#333', color: '#fff' } }} />
</div>
</div>
</APIProvider>
);
}
In _app.tsx, a warning also appears on the default App function:
Property 'settings' does not exist in type 'AppProps'.
I've researched solutions on Chatgpt suggesting to extend AppProps, but this hasn't resolved the issue. As a newcomer to TypeScript and Next JS, I'm seeking further guidance.