How to run ES6 React app in IE9 without errors - reactjs

I am working on a JS app using React 0.14 and Babel 5.8.23.
My app works fine in Chrome, with no warnings, but when I view the app in IE9 the app explodes showing:
SCRIPT5022: Exception thrown and not caught
on the line
ReactDOM.render(
When I trap the exception, it shows that it is being thrown from this code:
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
When I manually remove these throws from the generated index.js, the app proceeds normally, although I do see these warnings (possibly unrelated, and discussed at https://github.com/facebook/react/issues/4990):
Warning: MainLogo(...): React component classes must extend React.Component
All my components do extend React.Component:
import React, { Component } from 'react';
export default class MainLogo extends Component {
render() {
return (
<h1 className="logo">
<img src="/img/brand/logo.png" />
</h1>
);
}
};
Why would this _classCallCheck be being triggered in IE9, and what could I do differently to prevent it?

It turns out that the following are problems for IE9:
1.
import React, { Component } from 'react';
export default class Whatever extends Component { ...
I had to import React; and then ... extends React.Component.
2.
I had to export my connected components as non-top-level components, ie giving them a name within the file:
export class App extends React.Component {
...
}
export const AppContainer = connect(state => ({ routerState: state.router }), { pushState }) (App);
3.
I had to disable livereactload https://github.com/milankinen/livereactload, specifically removing it from .babelrc used by babel-plugin-react-transform.
Only completing ALL these steps allowed my app to run satisfactorily on IE9.

Related

Uncaught ReferenceError: require is not defined react-rails

I'm trying to integrate react-rails 2.6.1 within my rails 4.2.11 app.
initially started with webpacker but it's giving me troubles with the actual prod deployment, so I removed webpacker and just pack stuff with sprockets 3.7.2.
The page is loaded properly but the react_component is not shown.
in the html source it's just rendered as a div:
<div data-react-class="Sidebar" data-react-props="..." data-react-cache-id="Sidebar-0"></div>
but nothing is shown.
in the console I can see:
Uncaught ReferenceError: require is not defined
which causes later on:
Cannot find component: 'Sidebar'. Make sure your component is available to render.
this is the definition of my react component:
import React from "react"
class Sidebar extends React.Component {
render() {
return (<p> hello from react </p> );
}
}
I've tried moving imports from application.js up and down, (according to https://github.com/reactjs/react-rails/wiki/Troubleshooting) to no help.
Try to export your component to be able to import it
import React from "react"
class Sidebar extends React.Component {
render() {
return (<p> hello from react </p> );
}
}
export default Sidebar;

How to properly import a web component to react app?

I have a catalago-component.js which is a web component. I'm trying to use this web component like so:
import React from 'react'
import './../../../assets/catalago-component'
class Loja extends React.Component{
constructor(props){
super(props)
this.state = {}
}
render(){
return(
<React.Fragment>
<div className="page-header">
<h1 className="page-title">Loja</h1>
</div>
<catalago-component></catalago-component>
</React.Fragment>
)
}
}
export default Loja
but every time I run my react app I get this error
src\assets\catalago-component.js
Line 1:1: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:85: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:399: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:599: Expected an assignment or function call and instead saw an expression no-unused-expressions
...
but if I do any changes to the app that makes it recompile then it works just fine
how to solve this error forever? I don't want this app breaking every time I run it for the first time
EDIT: I tried to use this web component with pure html and it worked. take a look
https://eduardopreuss.github.io/web-component/
https://github.com/eduardopreuss/web-component
EDIT 2: link to codesandbox using react + web component https://codesandbox.io/s/hopeful-cohen-ut6mv?file=/src/App.js
I think you might want to try something like this:
import Catalago from './../../../assets/catalago-component'
Then use the component like:
<Catalago></Catalago>
Assuming your Web component issomething like this:
class Catalago extends React.Component {
render() {
return <speical-web-stuff><speical-web-stuff>
}
}
See:https://reactjs.org/docs/web-components.html
As said above, you should give your component a name in order to import.
import Catalago from './../../../assets/catalago-component'
However, sth you may pay attention to.
Below syntax expect your component is written in index.js under the folder catalago-component
import Catalago from './assets/catalago-component' //component locate in file name ```index```
import Catalago from './assets/catalago-component/customizedName.js'
which type of export used in that component
import Catalago from './assets/catalago-component/customizedName.js' // exporting via ```export default``` keyword
import { Catalago } from './assets/catalago-component/customizedName.js' //exporting via ```export``` keyword
Inside your webpack.config.js add this line
Than you can use your component from anywhere inside project.
import Catalago from 'Components'
There is nothing wrong how I imported, it was a eslint error just like #tsecheukfung01 said in the comments. So I added my web component to .eslintignore file and It worked just fine.
more ways to ignore eslint errors here
The way you import your component is perfectly fine.
A web-component is nothing more than any other HTMLElement like a <div> or an <a>, meaning this is NOT a React component and cannot be imported and used as such.
Example web-component
export class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `My Webcomponent!`
}
static get tag() {
return 'my-component';
}
}
customElements.define(MyComponent.tag, MyComponent);
Using the above web-component would look something like:
import './../../../assets/MyComponent.js'
...
render() {
return() {
<div>
<my-component></my-component>
</div>
}
}
import Catalago from './../../../assets/catalago-component'
...
render() {
return() {
<div>
<Catalago //other props/>
</div>
}
}

create-react-app, code splitting and jest

I'm developing an application using create-react-app and I'm trying to split my code into modules implementing the way described in the react-router huge-apps example.
Everything works well except the unit tests : I get this error while running the jest tests for the route components :
TypeError: Cannot read property 'contextTypes' of undefined
A route component looks like this :
export class IntroPage extends React.Component {
render() {
return (
<div></div>
);
}
}
const mapStateToProps = (state) => {
return {
...
}
};
module.exports = connect(mapStateToProps)(IntroPage);
and a test :
import React from 'react';
import {shallow} from 'enzyme';
import {IntroPage} from '../IntroPage';
it('should render without crashing', () => {
shallow(
<IntroPage {...props}/> // IntroPage is undefined
)
});
How do I have to export/import my components to be able to test them properly.
Thanks.
If you transpile in Babel:
export class IntroPage extends React.Component {
...
}
You will notice that Babel will move that to the exports variable.
Object.defineProperty(exports, "__esModule", {
value: true
});
... more good stuff
...
var IntroPage = exports.IntroPage = function (_React$Component) {
So you can console.log these:
console.log(exports);
console.log(module.exports);
console.log(module);
and check exports variable and module object.
In here module.exports should be the same as exports.
If you type:
module.exports = connect(mapStateToProps)(IntroPage);
at the end of your component file, you are overwriting the module.exports with the new value.
This is the core of the problem.
The solution?
I think you already found one, but the best would be not to mix commonJS with ES6 export, since ES6 export will be transpiled to commonJS syntax.
Check also "What is export default in JavaScript?"
Found a solution with this post : React router dynamic routes not rendering component
I just had to add 'default' to the require statements when exporting with es6 module.

React Mobx - component not updating after store change

Using Mobx, after updating the store (i.e. clicking the button) the component does not re-render. I've installed mobx devtools which shows nothing after the initial load, and there is no error in the console. Any ideas what I've done wrong?
Store.js:
import { observable } from 'mobx';
class Store {
#observable me;
constructor() {
this.me = 'hello';
}
change_me(){
this.me = 'test 1234';
}
}
export default Store;
layout.js:
import React from "react";
import { observer } from 'mobx-react';
#observer
export default class Layout extends React.Component{
render(){
return(
<div>
<h1>{this.props.store.me}</h1>
<button onClick={this.on_change}>Change</button>
</div>
)
}
on_change = () => {
this.props.store.change_me();
}
}
index.js:
import React from "react";
import ReactDOM from "react-dom";
import Layout from "./components/Layout";
import Store from "./Store";
import DevTools, { configureDevtool } from 'mobx-react-devtools';
// Any configurations are optional
configureDevtool({
// Turn on logging changes button programmatically:
logEnabled: true,
// Turn off displaying conponents' updates button programmatically:
updatesEnabled: false,
// Log only changes of type `reaction`
// (only affects top-level messages in console, not inside groups)
logFilter: change => change.type === 'reaction',
});
const app = document.getElementById('app');
const store = new Store();
ReactDOM.render(
<div>
<Layout store={store} />
<DevTools />
</div>
, app);
I would start by adding #action to your change_me() function. From what I understand, it's not always completely required, but I have encountered problems like this in my own code several times when I've forgotten to add it.
Additionally post your .babelrc as #mweststrate suggested, as it will help others to check that the proper plugins are loaded.
Just add makeObservable(this); in constructor function like below
constructor() {
makeObservable(this);
}
My guess would be to have uninitialized #observable. It is very counter-intuitive, but Babel doesn't handle those well. Even adding #observable me = undefined might help (see the generated js code when you assign something there. Generally I'd remove constructor completely and move the initialization to declaration (i.e. #observable me = "hello" an no constructor). It should then work fine.
Watch the binding of the this context.
<button onClick={this.on_change}>Change</button>
the this reference will not be to the class, so likely when you are actually clicking it is going to say something along the lines of no props on undefined. Changing to:
<button onClick={this.on_change.bind(this)}>Change</button>
should fix it. Or better yet, bind the context in the constructor so its not re-binding on every render
constructor(props) {
super(props)
this.on_change = this.on_change.bind(this)
}
then you can go back to your

RaisedButton not working at all

I have included material-ui (and react-tap-event-plugin) in my project and added 3 buttons to one of my components:
<RaisedButton onClick={this.props.onSave} label="Save" style={styles.button}/>
<RaisedButton label='Publish' onClick={this.props.onPublish} style={styles.button}/>
<RaisedButton label='Cancel' onClick={this.onCancel.bind(this)} style={styles.buttonCancel}/>
when I click on any of these, they go very dark grey and when I click again, they go black (and stay like that). The whole applications goes bonkers, the react routing no longer works (I can see the URL changing in the address bar, but the view doesn't refresh). This all looks pretty bad for a button click :)
Any idea what I may be doing wrong? (I take care of the childContext as described in the docs, so the muiTheme is loaded).
I forgot to check the console... there are 3 exceptions whenever I press the button:
1)
vendor.js:12 Uncaught Error: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded (details: https://facebook.github.io/react/warnings/refs-must-have-owner.html).(…)
2)
ReactTransitionGroup.js:176 Uncaught TypeError: Cannot read property 'componentWillLeave' of undefined(…)
3)
vendor.js:12 Uncaught Error: removeComponentAsRefFrom(...): Only a ReactOwner can have refs. You might be removing a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded (details: https://facebook.github.io/react/warnings/refs-must-have-owner.html).(…)
In the component that uses FlatButton (or RaisedButton neither work) I have this:
1) Import:
import FlatButton from 'material-ui/FlatButton'; //eslint-disable-line
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
2) in the class
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
3) and a static declaration:
EditorComponent.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
Feels like I'm doing all that's required.
This may be related to what I'm experiencing:
https://github.com/callemall/material-ui/issues/2818
So probably the issue is caused by material-ui distributing it's own version of React? What's the point in that? But... my version of material-ui doesn't have a node_modules folder, so no extra React either...
Source for a component importing and using FlatButton
import React from 'react'; // eslint-disable-line
import Input from '../../../components/common/textInput'; // eslint-disable-line
import BaseEditorComponent from '../base/EditorComponent';
import FlatButton from 'material-ui/FlatButton'; //eslint-disable-line
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
export default class EditorComponent extends BaseEditorComponent {
constructor() {
super();
this.state = {
textValue: 'Enter value'
};
}
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
_onChange(e) {
this.setState({
textValue: e.target.value
});
}
render() {
return (
<div>
<Input
value={this.state.textValue}
name="SimpleText"
label="Simple Text Value:"
onChange={this._onChange.bind(this)}
/>
<FlatButton label="Test"/>
</div>
);
}
}
EditorComponent.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
Also, the BaseEditorComponent:
import React from 'react';
import widgetActions from '../../widgets/WidgetActions';
import widgetInstanceStore from '../../widgets/WidgetInstanceStore';
export default class EditorComponent extends React.Component {
constructor() {
super();
}
componentDidMount() {
this.setState(widgetInstanceStore.getWidgetInstanceState(this.props.widgetId) || {});
}
save() {
widgetActions.saveWidgetInstanceState(this.props.widgetId, this.state);
}
}
Have you tried to use onTouchTap instead of onClick?
If #1 doesn't help, please show more code - component with above code and it's parent component.
As per https://github.com/callemall/material-ui/issues/2818 the solution was to include react-addons-transition-group alongside react in the browserify bundle. So it's good to know that it's not only NPM where a 2nd copy of react can slip through, but also browserify or webpack.
Thanks https://stackoverflow.com/users/3706986/piotr-sołtysiak for helping with the issue today!

Resources