Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In React, how do I detect if my component is rendering from the client or the server?

I'm building a isomorphic application, but I'm using a third-party component that only renders on the client. So, particularly for this component, I need to only render it when I'm rendering in the client.

How do I detect if I'm at the client or at the server? I'm looking for something like isClient() or isServer().

like image 242
AndrΓ© Pena Avatar asked Aug 26 '15 00:08

AndrΓ© Pena


People also ask

How do you check if React component is rendered?

Using React DevTools to highlight what components rerendered To enable it, go to "Profiler" >> click the "Cog wheel" on the right side of the top bar >> "General" tab >> Check the "Highlight updates when components render." checkbox.

How does a React component know when to re render?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.

Is React server side rendering?

React is a popular front-end framework used to create single-page applications (SPAs). It is rendered and run on the client-side in the browser. However, for SEO or performance reasons, you may need to render parts of a React application on the server. This is where the server-side rendering (SSR) is useful.


6 Answers

Internally, React uses a utility called ExecutionEnvironment for this. It implements a few useful properties like canUseDOM and canUseEventListeners. The solution is essentially just what's suggested here though.

The implementation of canUseDOM

var canUseDOM = !!(
  (typeof window !== 'undefined' &&
  window.document && window.document.createElement)
);

I use this in my application like this

var ExecutionEnvironment = require('react/node_modules/fbjs/lib/ExecutionEnvironment');
...
render() {
  <div>{ ExecutionEnvironment.canUseDOM ? this.renderMyComponent() : null }</div>
}

EDIT This is an undocumented feature that shouldn't be used directly. Its location will likely change from version to version. I shared this as a way of saying "this is the best you can do" by showing what the Facebook team uses internally. You may want to copy this code (it's tiny) into your own project, so you don't have to worry about keeping up with its location from version to version or potential breaking changes.

ANOTHER EDIT Someone created an npm package for this code. I suggest using that.

npm install exenv --save
like image 69
Charlie Martin Avatar answered Oct 19 '22 20:10

Charlie Martin


You can use reacts lifecyle events (e.g.: componentDidMount) to detect server/client side rendering.

Examples

As Hook

import { useState, useEffect } from 'react'

function useIsServer () {
  const [isServer, setIsServer] = useState(true)
  useEffect(() => {
    setIsServer(false)
  }, [])
  return isServer
}

Usage

See below (Functional Component)

As Functional Component

import useIsServer from './above'

function ServerOnly ({ children = null, onClient = null }) {
  const isServer = useIsServer()
  return isServer
    ? children
    : onClient
}

Usage

<ServerOnly
  children='This String was rendered on the server'
  onClient='This String was rendered on the client'
/>

As Class Component

class ServerOnly extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      isServer: true
    }
  }

  componentDidMount() {
    this.setState({
      isServer: false
    })
  }

  render () {
    const { isServer } = this.state
    const { children, onClient } = this.props
    return isServer
      ? children
      : onClient
  }
}

Usage

<ServerOnly
  children='This String was rendered on the server'
  onClient='This String was rendered on the client'
/>
like image 33
HaNdTriX Avatar answered Oct 19 '22 19:10

HaNdTriX


Two things that may be relevant:

Many projects use some convention where they set a global SERVER or CLIENT boolean so all your code can switch based off it. In your server bundle, set some global, like in this project

global.__SERVER__ = true;

And in your client bundle, set some global client to true, which you can achieve one way with Webpack's DefinePlugin

new webpack.DefinePlugin({
  __CLIENT__: true
})

With the above approach, you could switch based off that variable in willMount, or render, to do one thing on the server, and another on the client.

The second thing that may be helpful here is componentDidMount only runs on the client, but not on the server.

like image 43
Andy Ray Avatar answered Oct 19 '22 21:10

Andy Ray


You can also use componentDidMount(), as this lifecycle method is not run when the page is server-side rendered.

like image 26
JoeTidee Avatar answered Oct 19 '22 21:10

JoeTidee


You could also just use the use-ssr React hook

import useSSR from 'use-ssr'

const App = () => {
  var { isBrowser, isServer } = useSSR()

  // Want array destructuring? You can do that too!
  var [isBrowser, isServer] = useSSR()

  /*
   * In your browser's chrome devtools console you should see
   * > IS BROWSER: πŸ‘
   * > IS SERVER: πŸ‘Ž
   *
   * AND, in your terminal where your server is running you should see
   * > IS BROWSER: πŸ‘Ž
   * > IS SERVER: πŸ‘
   */
  console.log('IS BROWSER: ', isBrowser ? 'πŸ‘' : 'πŸ‘Ž')
  console.log('IS SERVER: ', isServer ? 'πŸ‘' : 'πŸ‘Ž')
  return (
    <>
      Is in browser? {isBrowser ? 'πŸ‘' : 'πŸ‘Ž'}
      <br />
      Is on server? {isServer ? 'πŸ‘' : 'πŸ‘Ž'}
    </>
  )
}

Example

like image 33
Alex Cory Avatar answered Oct 19 '22 20:10

Alex Cory


You can check if global window variable is defined or not. as in browser it should always be defined.

var isBrowser = window!==undefined
like image 34
Ramesh Pareek Avatar answered Oct 19 '22 21:10

Ramesh Pareek