React: React app not rendering in IE11 and below

Created on 22 Nov 2016  ·  49Comments  ·  Source: facebook/react

Do you want to request a feature or report a bug?
BUG

What is the current behavior?
App doesn't render in IE11 and below.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/reactjs/69z2wepo/).

  • Build React app with Webpack
  • Launch IE11 or below (not an emulator)
  • You will see a blank screen or half-compiled React app with the following error:
    24f8f6e8-afde-11e6-9a6f-a3cc6355f55c

What is the expected behavior?

  • To render as it does in Chrome, Firefox, etc.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
We've temporarily shrink-wrapped our dependencies so that we can continue to serve our app. We're starting to believe that it's coming from a dependency that react, apollo or webpack may be relying on...

Shrink-wrapped versions of our dependencies (left is the new one that's broken and the right one is the old one that continues to work across all browsers) https://www.diffchecker.com/SyaJUcsk

Unconfirmed

Most helpful comment

This bit me too after upgrading to React 15.4 and I had to spend some time figuring it out. So I'm posting this to help others in the same situation.

If you are using react-hot-loader v3 for hot-reloading in DEV environment you need to load react-hot-loader/patch after babel-polyfill does. So Webpack's entry field should look like the following to work correctly with react 15.4.x, react-hot-loader v3 and webpack-dev-server:

entry: [
   'babel-polyfill', // Load this first
   'react-hot-loader/patch', // This package already requires/loads react (but not react-dom). It must be loaded after babel-polyfill to ensure both react and react-dom use the same Symbol.
   'react', // Include this to enforce order
   'react-dom', // Include this to enforce order
   './index.js' // Path to your app's entry file
]

Hope this helps ;)

All 49 comments

@FarhadG thanks for the report. Can you try to reproduce the error in dev? A diff of dependencies isn't too useful alone, unfortunately.We'd need a reproducible test case or a stack trace to try and narrow down the root cause here.

Thanks for the quick response, @Aweary .

Did you want me to compile the app in development mode and test or start the webpack server in dev mode (i.e. hot reloading, etc.)

You will see a blank screen or half-compiled React app with the following error:

Have you tried following the link in that error? It should include the information explaining why the error happened.

I did, @gaearon. It didn't make sense why it would work in Chrome and Firefox but not in IE11 and below. Thoughts?

Maybe you enabled babel-plugin-react-inline-elements. It requires a Symbol polyfill and won't work without it. See https://github.com/facebook/react/issues/5138.

Going to give this a try, @gaearon, however, it's baffling that it's been working all along until a few days ago.

Did you want me to compile the app in development mode and test or start the webpack server in dev mode (i.e. hot reloading, etc.)

Either way, as long as React is not being built for production. This should at least give us a better idea of where the issue is occurring.

Looked through our codebase and we were not explicitly using babel-plugin-react-inline-elements nor were any of our configurations. Thanks for the suggestion, @gaearon.

So, we served our app in development and it appears to work, consistently, yet when we bundle in production, we see the same result. Let me know what information would be useful for us to help track this issue down, @Aweary.

@FarhadG Are you absolutely confident? Like maybe you use a preset that "optimizes" React which might include another preset, which might ultimately include that plugin.

@FarhadG I hit this on my current project and had to include the Symbol polyfill. I do this by adding a polyfills.js to my entry point that looks like:

/**
 * Place any polyfills here. This project uses core-js:
 * https://github.com/zloirock/core-js
 *
 * ES6:
 * https://github.com/zloirock/core-js/tree/master/es6
 */

//...

// We need Symbol support for some React optimizations
require('core-js/modules/es6.symbol')

Edit: We use the babel-preset-react-optimize package

That was our original idea after your suggestion, @gaearon. I followed these particular presets:

{
  "presets": ["es2015", "react", "stage-0"],
  "plugins": ["react-hot-loader/babel"]
}

... and didn't see them requiring anything to do with the optimization plugins.

Just gave it a try, for trying's sake, @nhunzaker, and the issue persists.

I'm having the same issue. However I have two apps - one running 15.1.0 and one running 15.4.0, on a more recent update path.

https://www.votesforschools.com/ (15.1.0)
https://admin.votesforschools.com/ (15.4.0)

In each case in IE11 the exception is this:

https://facebook.github.io/react/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%24%24typeof%2C%20type%2C%20key%2C%20ref%2C%20props%2C%20_owner%7D&args[]=

Which outputs:

Objects are not valid as a React child (found: object with keys {$$typeof, type, key, ref, props, _owner}).

However this is only happening in deployed production. If I do a production build locally and serve it from Python SimpleHTTPServer this exception does not trigger.

I just want to report this, but as of tomorrow I'm rolling off this project as I'm starting a new job in the new year so I won't have access to the source code after this.

These are the only babel plugins being used (this is from our www config, admin is again slightly different)

"babel-core": "^6.10.4",
"babel-eslint": "^6.1.0",
"babel-loader": "^6.2.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-react-transform": "^2.0.2",
"babel-plugin-transform-class-properties": "^6.10.2",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "^6.9.0",
"babel-runtime": "^6.9.2",

Update 1: In IE now getting an exception box on our dev environment (but not on production itself). Full text is:

Line: 213
Error: Objects are not valid as a React child (found: object with keys {$$typeof, type, key, ref, props, _owner, _store}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `CoreLayout`.

On Production it's just the above one, without the mention of CoreLayout (which is just the app wrapper that called ReactDOM.render)

Update 2:

I've done the above with the polyfill. I have checked in the console and Symbol is available however I am still getting this error

Update 3:

Checked the node_modules folder, babel-plugin-react-inline-elements is not included anywhere so for me not linked to that

Update 4:

One project was causing a bit of a red herring.

The project that is currently running on React 15.1.0 has had no dependency updates since October in the package.json file, however packages are marked with the caret ^ symbol - so when running on the CI that means it was updating to the major version anyway.

I've changed this to tilde version locking (i.e. ~ on versions) and it resolved the issue for that project.

I've rolled back the second project to 15.3.2 and it's also working fine now.

We'll need a complete project reproducing this to investigate.

Thanks for including your debugging strategies, @tanepiper. Here's what we did in trying to figure out what the problem is:

  • Disabled react-tap-event-plugin
  • Removed react-tap-event-plugin
  • Reverted react-tap-event-plugin from v2.x to v1.0.0
  • Launched the app in development mode in IE11 and realized that it's something to do with webpack building our react app in production mode
  • Installed dependencies and built the app with various node versions: v5.5.0, v6.3.0, v.6.6.0
  • Rolled back many weeks which helped us understand that it wasn't something that we introduced but rather a dependency
  • Locked down all dev-dependencies to ensure that it's not something with one of our building dependencies
  • Locked down all dependencies to ensure it's not one of our explicit dependencies
  • Disabled shrinkwrap and locked our package.json in accordance with our successful npm-shrinkwrap.json, which helped us understand that it's a sub dependency
  • Shrink-wrapped a set of node_modules that we knew to work and diffed them against the broken ones to help us understand which dependencies it could potentially be (as noted in our issues)
  • Shrink-wrapped only our dependencies and not our dev-dependencies which showed us that it's most likely an issue from one of our dependencies as our ETE environments were successful when installing from a npm-shrinkwrap.json that contained only locked down our dependencies
  • Tried the several suggestions from the issues noted above:

    • Ensuring we were not using babel-plugin-react-inline-elements

    • Ensuring we were not using babel-preset-react-optimize

    • Tried the require('core-js/modules/es6.symbol') polyfill

@gaearon See updates above - rolled back to 15.3.2 and it's working so it's a recent change. Also turns out the CI was pulling React 15.4 anyway instead of 15.1 due to incorrect package.json config.

I will attempt to see if I can draw out a reproducible case for this but digging in a little bit it looks like whatever generates children for https://github.com/facebook/react/blob/master/src/shared/utils/traverseAllChildren.js is passing an object, not an array and that's what is triggering this exception.

The problem is that React doesn't "recognize" its own element. This likely happens because of the failed $$typeof check. Somehow react and react-dom no longer "agree" on the $$typeof value which should be typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103.

This might mean that react and react-dom somehow get different results when testing for Symbol polyfill. For example if you load a polyfill after react initializes but before react-dom does, you might get this issue.

To debug it further I recommend finding this fragment in your bundle:

var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;

You should see it two times (once from react and once from react-dom):

screen shot 2016-11-30 at 19 01 14
screen shot 2016-11-30 at 19 01 00

Try adding logs of r value and see if they're different. If they are, you'd need to figure out why react and react-dom get different values when checking for existence of Symbol.

The reason this is new in 15.4.0 is because there only used to be one version of this code, but now it's in both packages (intentionally).

Update:

A coworker was able to find a workaround that involved removing the ReactDOM import from inside the .jsx file and instead listing it under the plugins section of webpack.config.js.

Original File Contents

webpack.config.js

plugins: [
    new webpack.ProvidePlugin({
      i18n: "i18next",
      '_': "lodash",
      'numeral': "numeral",
      React: "react"
    })
  ],

routes.jsx

import 'babel-polyfill';
import {render} from 'react-dom';
//**** snip  ***
ReactDOM.render(routes, document.getElementById('main'));

Updated Files

webpack.config.js
```plugins: [
new webpack.ProvidePlugin({
i18n: "i18next",
'_': "lodash",
'numeral': "numeral",
React: "react",
ReactDOM: "react-dom"
})
],

routes.jsx

import 'babel-polyfill';
//snip
ReactDOM.render(routes, document.getElementById('main'));

While this works, I still would like to get to the root cause.  For the record, here is what our **devDependencies** looks like:

"devDependencies": {
"alt": "^0.18.6",
"babel-core": "^6.18.2",
"babel-loader": "^6.2.8",
"babel-plugin-transform-es2015-classes": "^6.18.0",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-2": "^6.18.0",
"block-ui": "^2.70.1",
"chai": "^3.5.0",
"classnames": "^2.2.5",
"css-loader": "^0.26.0",
"enzyme": "^2.6.0",
"flux": "^3.1.0",
"history": "^4.4.0",
"i18next": "^4.1.0",
"json-loader": "^0.5.4",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-chai-plugins": "^0.8.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.1",
"karma-sinon": "^1.0.5",
"karma-sinon-chai-latest": "^0.1.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.8.0",
"lodash": "^4.17.2",
"moment": "^2.17.0",
"mocha": "^3.1.2",
"moment-timezone": "^0.5.9",
"node-sass": "^3.13.0",
"numeral": "^1.5.5",
"react": "15.4.1",
"react-addons-test-utils": "15.4.1",
"react-bootstrap": "^0.30.7",
"react-dom": "15.4.1",
"react-router": "^3.0.0",
"react-waypoint": "^4.1.0",
"sass-loader": "^4.0.2",
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0",
"style-loader": "^0.13.1",
"superagent": "^3.0.0",
"vulcan": "git+ssh://[email protected]/mdsol/vulcan#2.2.2",
"webpack": "^1.13.3"
},
```

Have you had a chance to try my suggestion from the comment above? https://github.com/facebook/react/issues/8379#issuecomment-263962787

@gaearon I'm encountering this issue as well. I narrowed it down to some combination of react + babel-polyfill or babel-plugin-transform-runtime. I'll try to get a reduced test case going soon.

It would really help if you could follow my suggestion above and let me know your findings.
Thanks!

OK here is the change that I made in both spots:

var n="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103; 
debugger; console.log(n); e.exports=n}

Result from chrome:
image

Result from IE11
image

Great! As you can see they are different. Can you now try to look into what makes Symbol exist in one case but not the other? Could it be a polyfill you are loading too late?

I fixed this by enforcing a load order in my webpack bundle:

  1. babel-polyfill
  2. react
  3. react-dom

Thanks for your patience and your infinite wisdom 😉 @gaearon

I’m going to close this because it doesn’t appear to be a bug. It’s unfortunate this broke some apps but it’s very hard to protect against cases like this. In general my recommendation is that you should run any global polyfills before any other code in the bundle. Since polyfills are effectively modifying the environment, one should take care to do that consistently.

@damonbauer whole babel-polyfill is heavy, you can add only Symbol polyfill (https://github.com/thejameskyle/babel-react-optimize/issues/16#issuecomment-263519239)

Thank you to everyone on this thread, esp. @gaearon and @damonbauer. In case this helps someone else, here are the changes I ended up making:

image

This bit me too after upgrading to React 15.4 and I had to spend some time figuring it out. So I'm posting this to help others in the same situation.

If you are using react-hot-loader v3 for hot-reloading in DEV environment you need to load react-hot-loader/patch after babel-polyfill does. So Webpack's entry field should look like the following to work correctly with react 15.4.x, react-hot-loader v3 and webpack-dev-server:

entry: [
   'babel-polyfill', // Load this first
   'react-hot-loader/patch', // This package already requires/loads react (but not react-dom). It must be loaded after babel-polyfill to ensure both react and react-dom use the same Symbol.
   'react', // Include this to enforce order
   'react-dom', // Include this to enforce order
   './index.js' // Path to your app's entry file
]

Hope this helps ;)

Hi,

@gaearon, here's my investigation in order to answer https://github.com/facebook/react/issues/8379#issuecomment-263962787

Facing the same issue I tried to see why React.isValidElement was not recognizing some react elements.
Looking through react and react-dom code, I thought that there was no reason why react and react-dom would not agree on what REACT_ELEMENT_TYPE was, unless you require the polyfill between requiring react and react-dom for the first time. But importing them together should not cause a problem.

Indeed, https://github.com/facebook/react/blob/v15.4.2/src/shared/utils/ReactElementSymbol.js#L17 is declared at module loading time and used everywhere in the library. So generating elements with ReactDOM.render should not have been an issue, it had to come from somewhere else.

I ended up finding that the elements causing an issue were created by babel-runtime, because the logic from ReactElementSymbol was duplicated there, but with the presence of the polyfill:
https://github.com/babel/babel/blob/v6.22.0/packages/babel-helpers/src/helpers.js#L20

There is an issue closed as 'won't fix' on babel-runtime: https://github.com/babel/babel/issues/2517 because react won't share the REACT_ELEMENT_TYPE variable.

In my case, I am guessing that the issue is not due to our upgrade to 15.4 but a change of structure in our application. We can now understand why we need to import the polyfill beforehand, and it's because of babel-runtime and not react.

Hope this will help others being in the same scenario.

hi @leondragan ,
I still face the issue with the re-order. Which transform plugin should I added in .babelrc?

Thanks

This is a react-hot-loader issue because I only have it in dev mode and I'm not having it in production mode.
Adding babel-polyfill before react-hot-loader/patch fixes this bug.

In case somebody else comes across this, I was using the commons chunk plugin which was loading react in before the poly. To get around this I ended up with:

entry: {
    'commons': ['babel-polyfill', 'react', 'react-dom'],
    'app': './src/js/app/main.tsx'
}

Not sure if that is the 'right' way but it is the only way with commons I found that worked.

@andrewdavidcostello thanks for saving my day :)

For those who has the error, but nothing above worked: I've had same exact error, but the cause was completely different. There was code where react components were shared between iframes, but components to have different $$typeof value in different iframes, which caused the error. Although this worked with other browsers, IE11 had the error.

I was able to get this working by just including the 'core-js/modules/es6.symbol' BEFORE 'react'.

'core-js/modules/es6.symbol' is much smaller than 'babel-polyfill' so others may want to consider trying this as well

bitmoji

I tried all of the above and none of it worked except for a tweak on @jkilesc 's work. So the order of imports matter.

You would think your entry script having the polyfills at the top would be different than including it as a separate file in your entry array like babel-polyfill? No.

So from

// index.js
require('core-js/modules/es6.symbol')
require('core-js/modules/es6.promise')
import React from 'React'

to

// webpack.config.js
...
  entry: {
    polyfill: [
      path.resolve(__dirname, '../src/polyfill.js'),
    ],
    main:
...

plugins:[
...
    new webpack.optimize.CommonsChunkPlugin({
      // The order of this array matters
      names: ["main", "vendor", "polyfill"],
      minChunks: 2
    }),
...
]
...

// index.js
- require('core-js/modules/es6.symbol')
- require('core-js/modules/es6.promise')

// polyfill.js
// Absolutely ensure these are loaded first
require('core-js/modules/es6.symbol')
require('core-js/modules/es6.promise')

Why? During the transpile the order of libraries seems to shift so that the polyfill is loaded after React? But there you go. This also worked where babel-polyfill on my entry script did not.

This is expected to not work:

require('core-js/modules/es6.symbol')
require('core-js/modules/es6.promise')
import React from 'React'

ES imports are hoisted by spec (which Babel follows).
Even if you put require() before it, it will be executed later.

Use this lint rule to protect against this in the future.

You're right. Exactly as I ended up discovering. The reason I posted my solution is that this is the number one google result and I may not be alone in my lack of understanding as to the internals that make this work. Just trying to save the next guy a couple hours :) And thanks! That linter rule is def getting added.

Sure, thanks for posting! I didn't mean to say you don't understand the issue. Just pointing out for future readers that this behavior is expected (and not a bug in either Webpack or Babel).

Just to someone that is still facing issues with this, I've moved the babel-polyfill to the end on webpack config.

Solution Found here:
https://stackoverflow.com/questions/40897966/objects-are-not-valid-as-a-react-child-in-internet-explorer-11-for-react-15-4-1#comment69150679_40928047

So what is finally the best approach here?
Should we understand it's an issue with the order of the loading of those polyfills, and that the example provided by @notsoluckycharm should be the way to go?

@qborreda The solution is to load babel-polyfill before react and react-dom.

For Webpack users this means making the main entry an array and the first element of the array is gonna be babel-polyfill, as shown here:
https://github.com/catamphetamine/webpack-react-redux-isomorphic-render-example/blob/4d6208662157cfc6bac115fe5dff956c4976145c/client/webpack/webpack.config.js#L23

I ran into this when adding babel-polyfill to our react-redux app that was made using the asp.net core 2 template. This template splits up your webpack config into two separate configuration files (webpack.config.js and webpack.config.vendor.js). You need to modify the vendor array in webpack.config.vendor.js and put babel-polyfill at the top in order to get this to work.

I also had to fully clean up my environment (namely delete the wwwroot/dist folder) and rebuild the project in order for the changes to get properly picked up.

This just started happening to me again in the last week in IE11 (ive resolved this same bug in the past using the above suggestions).

  "dependencies": {
    "babel-core": "^6.17.0",
    "babel-loader": "^6.2.5",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-plugin-transform-runtime": "^6.15.0",
    "babel-polyfill": "^6.16.0",
    "babel-preset-es2015": "^6.14.0",
    "babel-preset-react": "^6.11.1",
    "babel-preset-stage-0": "^6.3.13",
    "babel-runtime": "^6.11.6",
    "better-npm-run": "0.0.11",
    "classnames": "^2.2.5",
    "css-loader": "^0.25.0",
    "currency-formatter": "^1.0.2",
    "debug": "^2.2.0",
    "exports-loader": "^0.6.3",
    "extract-text-webpack-plugin": "^1.0.0",
    "file-loader": "^0.9.0",
    "formsy-react": "^0.18.1",
    "fs-extra": "^0.30.0",
    "html-webpack-plugin": "^2.22.0",
    "imports-loader": "^0.6.5",
    "ip": "^1.1.2",
    "json-loader": "^0.5.4",
    "lodash": "^4.11.2",
    "moment": "^2.10.6",
    "node-sass": "^3.4.2",
    "normalize.css": "^4.1.1",
    "numeral": "^1.5.3",
    "pure-render-decorator": "^1.1.0",
    "react": "^15.0.0",
    "react-ab-test": "^2.0.1",
    "react-bootstrap": "^0.30.3",
    "react-cookie": "^1.0.5",
    "react-datetime": "^2.6.0",
    "react-document-meta": "^2.0.3",
    "react-dom": "^15.0.0",
    "react-redux": "^4.4.5",
    "react-router": "^2.8.0",
    "react-router-scroll": "^0.2.0",
    "react-select": "1.0.0-rc.1",
    "react-slick": "^0.14.3",
    "react-sticky": "^5.0.5",
    "react-telephone-input": "^3.5.0",
    "redux": "^3.6.0",
    "redux-thunk": "^2.0.0",
    "rimraf": "^2.5.4",
    "sass-loader": "^4.0.0",
    "seamless-immutable": "^6.1.0",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.6",
    "validator": "^5.2.0",
    "webpack": "^1.12.14",
    "whatwg-fetch": "^1.0.0",
    "yargs": "^5.0.0"
  },

The error:

SCRIPT5022: Objects are not valid as a React child (found: object with keys {$$typeof, type, key, ref, props, _owner, _store}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of 'RedBoxError'.
File: vendor.ab56ae7d3f092ad6e17f.js, Line: 1391, Column: 6

Nothing worked for me either, changing the order of the polyfill or anything else.
What worked for me is adding this JS link in the index.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.15/browser-polyfill.min.js"></script>

After adding this I was successfully able to run the react app in IE 11

Hello Guys I had similar issue but then in my index.js i used
and my issue was resolved.

I have read all the comments and if I read correctly, both working solutions are either, eject the webpack config or add cdn package, just to support IE11?

You don't need to add anything to webpack config.

React 16 requires a few runtime JS features that are missing in IE11, but easy to add with polyfills.

See here for how to add them: https://reactjs.org/docs/javascript-environment-requirements.html

Just make sure you put those imports in the entry point of your application, before any other imports.

If this didn't help, you might be having the same problem as https://github.com/facebook/react/issues/8379#issuecomment-263962787. TLDR is that if you choose to polyfill Symbol (React doesn't require it), make sure this polyfill runs before both react and react-dom. So also put it before any other imports in the entry point file.

I'm going to lock to prevent further confusion since comments about webpack are already confusing people into ejecting, which is absolutely unnecessary for this.

But if you do have a custom webpack config then maybe your problem is similar to https://github.com/facebook/react/issues/8379#issuecomment-338826578 which provides a clue about how to fix it.

Was this page helpful?
0 / 5 - 0 ratings