1

Access variable from script inside React component

I am doing device detection on Node and sending this object to the client(React) inside of index.ejs

<script  type="text/javascript">window.deviceType = <%- deviceType %></script>

Inside of React component if I console.log window.deviceType I see it running good but if I try to use it it says error, window is not defined.

For example, this is inside react component

    return(
      <div>
       <Menu.Item>
         {window.deviceType.isMobile ? (
            <Link to="/">
                <h1>React Boilerplate 23</h1>
            </Link>
         ) : (
                 <div>PROBLEM</div>
          )}
        </Menu.Item>
        <div type="button" onClick={() => console.log(window.deviceType)}>
          XX
        </div>
       </div>
     )

I can console.log it normal but it doesnt work when using logic so in the example above rendering doesnt work but console.log works.

The same stuff is happening if I try to do it like this

<script  type="text/javascript">var deviceType = <%- deviceType %></script>
3
  • Yes. I use SSR. But to be able to render specific stuff for mobile or desktop, I detect device on node and send it to client. Yes, that what it says window is not defined, but if I just console.log(window) it works ok. Commented Aug 29, 2018 at 22:11
  • Because the code inside onclick callback is evaluated only on client side. Commented Aug 29, 2018 at 22:11
  • Yes. I see what you are aiming at. So how can I use the variable from script when the code is SSR? Commented Aug 29, 2018 at 22:14

1 Answer 1

1

window is consistently available in browser and the original code cannot cause window is not defined error on client side. This can only happen if React application is rendered on server side.

window.deviceType.isMobile ? expression is evaluated on server side, while onClick callback is called on client side so it doesn't cause an error.

global.window = global in Node.js wouldn't be appropriate because the value is not global but specific to current request.

A proper approach is to decouple deviceType from window and provide a value globally for the application in ways that are specific to React, i.e via prop, state or context. A value can be passed as a prop from entry point. A value can be stored to Redux store if it's in use. Or React context can be used to make it available globally within the app:

export const DeviceTypeContext = React.createContext();

...

<DeviceTypeContext.Consumer>
  {deviceType => (
   <Menu.Item>
     {window.deviceType.isMobile ? (...) : (
             <div>PROBLEM</div>
      )}
    </Menu.Item>
  )}
</DeviceTypeContext.Consumer>

On client side:

render(
  <DeviceTypeContext.Provider value={window.deviceType}>
    <App />
  </DeviceTypeContext.Provider>,
  ...
);

On server side:

renderToString(
  <DeviceTypeContext.Provider value={someVariable}>
    <App />
  </DeviceTypeContext.Provider>,
  ...
);
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks estus. This works. Just a note for everyone that is doing server side rendering. Be sure to pass the same deviceType to StaticRouter(react-router-4). Also give deviceType some default value. This way, you can use, "isMobile", "isTablet" inside your react components and when you are doing SSR, depending the device you are on, only that will be renderedToString. Pretty cool and clean solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.