I have a next.js application that uses the context api. However i am having what appears to be a hydration issue? But im unsure how to fix it.
next-dev.js?3515:32 Warning: Did not expect server HTML to contain the text node " " in . at div at eval (webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js:55:66) at Box (webpack-internal:///./node_modules/@mui/system/esm/createBox.js:35:72) at Loading at AppProvider (webpack-internal:///./src/contexts/app/AppContext.tsx:177:9) at MyApp (webpack-internal:///./src/pages/_app.tsx:47:27) at StyleRegistry (webpack-internal:///./node_modules/styled-jsx/dist/stylesheet-registry.js:231:34) at ErrorBoundary (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:26:47) at ReactDevOverlay (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:90:23) at Container (webpack-internal:///./node_modules/next/dist/client/index.js:331:9) at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:770:26) at Root (webpack-internal:///./node_modules/next/dist/client/index.js:891:27)
The error suggests that it is something to do with my app context but im not sure what it is.
I have reproducible example of the code here.
https://codesandbox.io/s/interesting-mendel-d4dlu
- Login using 123, 123
- Refresh the page with the refresh button in the inbuilt codesandbox browser
View the console log error
AppContext
import React, { Component, ReactElement, createContext } from "react";
import { createTheme } from "@mui/material/styles";
import { IAuthenticateUser, Authenticate, VerifyAuthentication } from "../../services/AuthService";
import { Loading } from "../../components/loading/Loading";
export interface IAppProviderProps {}
export interface IAppProviderState {
user: any | null;
token: string | null;
setUser?: any;
isAuthenticated?: boolean;
setDarkMode?: any;
theme: any;
isLoading?: boolean;
}
const DEFAULT_THEME = createTheme({
typography: {
fontSize: 12,
},
palette: {
mode: "light",
primary: {
main: "#212121",
},
secondary: {
main: "#fafafa",
},
},
});
const DARK_THEME = createTheme({
typography: {
fontSize: 12,
},
palette: {
mode: "dark",
primary: {
main: "#212121",
},
secondary: {
main: "#fafafa",
},
},
});
const INITIAL_STATE: IAppProviderState = { user: null, token: null, theme: DEFAULT_THEME, isAuthenticated: false };
export const AppContext = createContext(INITIAL_STATE);
export class AppProvider extends Component<IAppProviderProps, IAppProviderState> {
constructor(props: IAppProviderProps) {
super(props);
const data = this.getUser();
if (data) {
this.state = {
user: data.user,
token: data.token,
theme: INITIAL_STATE.theme,
isLoading: true,
};
} else {
this.state = INITIAL_STATE;
}
}
componentDidMount = async () => {
if (this.state.token) {
const isAuthenticated = await this.isUserAuthenticated(this.state.token);
this.setState({ isAuthenticated: isAuthenticated, isLoading: false });
}
};
setUser = async (payload: IAuthenticateUser): Promise<boolean> => {
const response = await Authenticate(payload);
if (response && response.status === 200) {
this.setState({
user: response.data.user,
token: response.data.token,
isAuthenticated: true,
});
return true;
}
return false;
};
setDarkMode = async (toggle: boolean): Promise<void> => {
const theme = toggle ? DARK_THEME : DEFAULT_THEME;
this.setState({
theme: theme,
});
};
componentDidUpdate = (prevProps: IAppProviderProps, prevState: IAppProviderState) => {
if (this.state.user !== prevState.user || this.state.token !== prevState.token) {
console.log("didupdate");
this.syncUser();
}
};
syncUser = () => {
localStorage.setItem("token", JSON.stringify(this.state.token));
localStorage.setItem("user", JSON.stringify(this.state.user));
};
getUser = () => {
try {
const user = localStorage.getItem("user");
const token = localStorage.getItem("token");
if (!user || !token) {
return null;
}
const response = {
user: JSON.parse(user),
token: JSON.parse(token),
};
return response;
} catch (err) {
return null;
}
};
isUserAuthenticated = async (token: any): Promise<boolean> => {
try {
const response = await VerifyAuthentication(token);
if (response.status !== 200) {
return false;
}
return true;
} catch (err) {
return false;
}
};
render(): ReactElement {
if (this.state.isLoading) {
return <Loading />;
} else {
return (
<AppContext.Provider
value={{
theme: this.state.theme,
user: this.state.user,
setUser: this.setUser,
setDarkMode: this.setDarkMode,
token: this.state.token,
isAuthenticated: this.state.isAuthenticated,
isLoading: this.state.isLoading,
}}
>
{this.props.children}
</AppContext.Provider>
);
}
}
}
if (this.state.isLoading) { return <Loading />; } else {
– Kay