React SSR: Document is not defined
Solution 1
This issue usually happens because when react is rendered on the server. It does not have a document or window object on the server side and those objects are only available on the browser.
Try to call the document functions in or after componentDidMount
.
componentDidMount(){
this.setState({documentLoaded:true});
}
someFunction(){
const { documentLoaded } = this.state;
if(documentLoaded){
// LOGIC USING DOCUMENT OBJECT
}
}
Solution 2
If you are using react-hooks, you can create your custom useDocument hook:
import React, { useEffect, useState } from 'react'
export const useDocument = () => {
const [myDocument, setMyDocument] = useState(null)
useEffect(() => {
setMyDocument(document)
}, [])
return myDocument
}
in your component:
...
const doc = useDocument()
...
<SomeComponent
ref={doc && doc.body}
...
/>
...
ZpfSysn
Updated on June 19, 2022Comments
-
ZpfSysn almost 2 years
I have been working on this for two days now. Looked through multiple stack posts and still not found a suitable answer.
I am trying to rendering my react project in server like following:
Server.js
function handleRender(req,res){ const sheetsRegistry = new SheetsRegistry(); const sheetsManager = new Map(); const theme = createMuiTheme({ palette:{ primary:green, accent: red, type: 'light', } }) const generateClassName = createGenerateClassName(); const html = ReactDOMServer.renderToString( <JssProvider registry={sheetsRegistry} generateClassName={generateClassName}> <MuiThemeProvider theme={theme} sheetsManager={sheetsManager}> <TwoFA /> </MuiThemeProvider> </JssProvider> ) const css = sheetsRegistry.toString() res.send(renderFullPage(html,css)) } function renderFullPage(html,css){ return ` <!DOCTYPE html> <html> <head> <title>2FA SDK</title> </head> <body style="margin:0"> <div id="app">${html}</div> <script id="jss-server-side">${css}</script> </body> </html> ` }
Client.js:
import React from 'react'; import ReactDOM from 'react-dom'; import TwoFA from './App'; import { MuiThemeProvider, createMuiTheme, createGenerateClassName, } from '@material-ui/core/styles'; import green from '@material-ui/core/colors/green'; import red from '@material-ui/core/colors/red'; class Main extends React.Component{ componentDidMount() { const jssStyles = document.getElementById('jss-server-side'); if (jssStyles && jssStyles.parentNode) { jssStyles.parentNode.removeChild(jssStyles); } } render(){ return <TwoFA /> } } const theme = createMuiTheme({ palette: { primary: green, accent: red, type: 'light', }, }); const generateClassName = createGenerateClassName(); if (typeof window !== 'undefined'){ ReactDOM.hydrate( <JssProvider generateClassName={generateClassName}> <MuiThemeProvider theme={theme}> <TwoFA/> </MuiThemeProvider> </JssProvider>, document.querySelector('#app'), ); }
Webpack.config.js
module.exports = [ { /*Config for backend code*/ entry: './src/server/server.js', output: { filename: 'server.js' }, externals: [nodeExternals()], module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: "babel-loader" } }, { test: /\.html$/, use: { loader: "html-loader", options: { minimize: true } } }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader,"css-loader"] } ] }, plugins: [ new HtmlWebPackPlugin({ template: "./public/index.html", filename:"./index.html" }), new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename:"[id].css" }) ] }, { entry: './src/client.js', output: { filename: 'bundle.js', }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', }, { test: /\.html$/, use: { loader: "html-loader", options: { minimize: true } } }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader,"css-loader"] } ], }, plugins: [ new HtmlWebPackPlugin({ template: "./public/index.html", filename:"./index.html" }), new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename:"[id].css" }) ] } ]
What I have tried: I search on SO and found that many posts suggesting put a condition check like so :
if (typeof window !== 'undefined')
. However, this does not solve the problem.I also understood that the error is due to the fact that during SSR, server-side has no document project.
I have searched on github issue page and someone mentioned that he ran into the problem with webpack, but same project worked fine with browserify.
What I need help with: I am trying to solve this problem as it cause the app to break.
I am suspecting that there is something wrong with webpack. I am looking a fix for this