Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Flow cannot call ReactDOM.render with document.getElementById(...)

I was getting this error below in Flow type checking.

Cannot call ReactDOM.render with document.getElementById(...) bound to container because null [1] is
incompatible with Element [2].

     src/index.js
      26│       </Switch>
      27│     </ScrollToTop>
      28│   </BrowserRouter>
      29│ </Provider>, document.getElementById("root"));
      30│

     /private/tmp/flow/flowlib_174a8121/dom.js
 [1] 646│   getElementById(elementId: string): HTMLElement | null;

     /private/tmp/flow/flowlib_174a8121/react-dom.js
 [2]  18│     container: Element,

The code is below.

// @flow
"use strict";
import React from "react";
import ReactDOM from "react-dom";
import {createStore, applyMiddleware} from "redux";
import {Provider} from "react-redux";
import {BrowserRouter, Switch, Route} from "react-router-dom";
import Home from "./components/home";
import Detail from "./components/detail";
import LevelOfGame from "./components/level-of-game";
import NotFound from "./components/not-found";
import ScrollToTop from "./components/scroll-to-top";

import reducers from "./reducers";

const createStoreWithMiddleware = applyMiddleware()(createStore);

ReactDOM.render(<Provider store={createStoreWithMiddleware(reducers)}>
  <BrowserRouter>
    <ScrollToTop>
      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/detail/:detailId" component={Detail}/>
        <Route path="/level-of-game" component={LevelOfGame}/>
        <Route path="*" component={NotFound} status={404}/>
      </Switch>
    </ScrollToTop>
  </BrowserRouter>
</Provider>, document.getElementById("root"));

I believe I had to specify the type somehow in getElementById.

So I fixed the error by storing document.getElementById("root"); in a constant variable with a type specification:

const root: any = document.getElementById("root");

The error is fixed and I hope this is useful for other folks, but I'd love to understand what was causing this error. Can anyone be so kind to tell me what this was?

like image 319
sflow Avatar asked May 30 '18 03:05

sflow


People also ask

How do you render with ReactDOM?

The ReactDOM. render() function takes two arguments, HTML code and an HTML element. The purpose of the function is to display the specified HTML code inside the specified HTML element.

Is ReactDOM render necessary?

Because you won't be able to render an app to DOM without it. Your app probably has reactdom. render() in it and you don't realize it. Those are probably standalone examples—you need it once for every app.

What is the difference between ReactDOM render and render?

Wrapping Up. As the article says both the render() and hydrate() function are part of the ReactDOM package for displaying content to the user. Difference between them is that with render() function all content is render at the client side, which means that both HTML and JS part would be rendered on client side.

What does ReactDOM render return?

render() currently returns a reference to the root ReactComponent instance. However, using this return value is legacy and should be avoided because future versions of React may render components asynchronously in some cases.


1 Answers

Aleksey L. got this first in the comments, I wanted to bring this info up to the answer level for easier visual scanning.

Flow is letting you know that the call document.getElementById("root"); can return null in which case the app would completely crash. So let's guard against that:

const root = document.getElementById('root')

if (root !== null) {
  ReactDOM.render(<App /> , root)
}

Granted, this can feel a little annoying given that in all likelihood you will be controlling the HTML you are rendering into.

like image 116
cogell Avatar answered Oct 06 '22 09:10

cogell