mizech mizech - 2 months ago 21
React JSX Question

React : Application works on desktop but on mobile a blank page is shown

I've made this app with React:

calculator app

Live-Demo here: http://n-or.de/simple-calculator/

It works well on desktop but on mobile the actual app isn't visible.

One just sees the background with the gradient. I've tested that with an iPhone 6s plus. Afterward I asked a friend to try it on her Android and she had the same blank background.

That's already the second React app with which I have this issue.

The mentioned other React app can be seen here: http://n-or.de/weather-app/

So I don't think it's attached to using some specific language feature.

Here's the JSX- and Sass-code of the calculator app:



// Main.jsx as starting point of the app.
var React = require('react');
var ReactDOM = require('react-dom');
var Calculator = require('./components/Calculator.jsx');

var NAV_BUTTONS = [
{ value: '+ Add',
operation: 'add'
},
{ value: '- Subtract',
operation: 'subtract'
},
{ value: 'x Multiply',
operation: 'multiply'
},
{ value: '/ Divide',
operation: 'divide'
}
];

ReactDOM.render(<Calculator navButtons={ NAV_BUTTONS } />, document.getElementById('app'));

// Calculator.jsx - Main app-component
var React = require('react');
var TextBox = require('./TextBox.jsx');
var Button = require('./Button.jsx');

var Calculator = React.createClass({
INIT_STATE: { a: 0,
b: 0,
placeholderText: 'Enter a number ...',
resultBox: '',
aClass: 'input-box',
bClass: 'input-box',
aDisabled: false,
bDisabled: false,
buttonsDisabled: 'disabled' },
operations: {
'add': function() {
return this.state.a + this.state.b;
},
'subtract': function() {
return this.state.a - this.state.b;
},
'multiply': function() {
return this.state.a * this.state.b;
},
'divide': function() {
return this.state.a / this.state.b;
}
},
getInitialState: function() {
return this.INIT_STATE;
},
updateNumbers: function(variable, reference) {
var val = parseFloat(reference.value);
var varClass = [variable + 'Class'];

if (typeof val === 'number' && !isNaN(val)) {
if (this.state[variable + 'Class'].indexOf('invalid-input') > -1) {
this.setState({
[varClass]: 'input-box'
})
}

this.setState({
[variable]: val,
buttonsDisabled: ''
});
} else {
this.setState({
[varClass]: [varClass] + ' invalid-input',
buttonsDisabled: 'disabled'
});
}
},
triggerOperation: function(operation) {
var result = this.operations[operation].call(this);

this.setState({
aDisabled: 'disabled',
bDisabled: 'disabled',
buttonsDisabled: 'disabled'
});

this.refs.resultBox.refs.inputElement.value = result;
},
resetForm: function() {
function resetElement(itemName, placeholder, disabled) {
this.refs[itemName].refs.inputElement.value = ''; // Value must be empty f. placeholder to appear.
this.refs[itemName].refs.inputElement.disabled = disabled;
this.refs[itemName].refs.inputElement.placeholder = placeholder;
}

resetElement.call(this, 'a', this.INIT_STATE.placeholderText);
resetElement.call(this, 'b', this.INIT_STATE.placeholderText);
resetElement.call(this, 'resultBox', this.INIT_STATE.resultBox, 'disabled');

this.setState({
a: 0,
b: 0,
aClass: 'input-box',
bClass: 'input-box',
buttonsDisabled: 'disabled'
});
},
render: function() {
var that = this;

var navButtons = this.props.navButtons.map(function(button) {
return (
<div>
<Button value={ button.value } classDiv="large-3 medium-6 column"
classButton="calculation-method nav-button"
handler={ that.triggerOperation } operation={ button.operation } disabled={ that.state.buttonsDisabled }/>
</div>
);
});

return (
<div className="calculator">

<div className="row">
<h1>Simple calculator</h1>
</div>

<div className="row">
<TextBox divClass="large-6 columns"
placeholder={ this.state.placeholderText }
id="a" textBoxClass={ this.state.aClass }
ref="a"
value={ this.state.a }
changeHandler={ this.updateNumbers }
variable="a"
disabled={ this.state.aDisabled }
/>
<TextBox divClass="large-6 columns"
placeholder={ this.state.placeholderText }
id="b" textBoxClass={ this.state.bClass }
ref="b"
value={ this.state.b }
changeHandler={ this.updateNumbers }
variable="b"
disabled={ this.state.bDisabled }
/>
</div>

<div className="row">
{ navButtons }
</div>

<div className="row">
<TextBox divClass="medium-9 columns"
placeholder={ this.INIT_STATE.resultBox }
ref="resultBox" textBoxClass="input-box"
disabled="disabled" />
<Button value="Clear" classDiv="medium-3 columns"
classButton="attention nav-button"
handler={ this.resetForm } />
</div>
</div>
);
}
});

module.exports = Calculator;

// Button component
var React = require('react');

var Button = React.createClass({
render: function() {
function notify(e) {
this.props.handler(e.target.dataset.operation);
}

return (
<div className={ this.props.classDiv }>
<button href='#' className={ this.props.classButton }
onClick={ notify.bind(this) }
data-operation={ this.props.operation }
disabled={ this.props.disabled } >
{ this.props.value }
</button>
</div>
);
}
});

module.exports = Button;

// TextBox component
var React = require('react');

var TextBox = React.createClass({
notify: function() {
let item = this.refs.inputElement;

this.props.changeHandler(item.dataset.variable, item);
},
render: function() {
return (
<div className={ this.props.divClass }
ref={ this.props.id }>
<input type="text"
placeholder={ this.props.placeholder}
ref="inputElement"
className={ this.props.textBoxClass }
disabled={ this.props.disabled }
onChange={ this.notify }
data-variable={ this.props.variable }
/>
</div>
);
}
});

module.exports = TextBox;

$lightChange: 25%;
$borderRadius: 6px;

@mixin addPseudoClasses($selector, $color) {
#{$selector}:visited, #{$selector}:hover {
color: white;
}

#{$selector}:hover {
background: linear-gradient(lighten($color, $lightChange), $color);
color: white;
cursor: pointer;
}

#{$selector}:active {
opacity: 0.6;
box-shadow: 1px 1px 0 black;
}
}

html, body {
height: 100%;
}

body {
background: linear-gradient(to top, #403B4A , #E7E9BB);
}

.nav-button {
text-decoration: none;
color: green;
padding: 10px 20px;
text-align: center;
font-weight: 900;
font-size: 1.2rem;
margin-bottom: 16px;
display: inline-block;
width: 100%;
border-radius: $borderRadius;
letter-spacing: 1px;
box-shadow: 2px 2px 0 black;
}

.nav-button[disabled] {
color: crimson;
}

.calculation-method {
background: linear-gradient(to top, #abbaab ,#ffffff);
}

@include addPseudoClasses('.calculation-method', #344334);

h1 {
text-align: center;
margin: 20px 0 30px;
letter-spacing: 2px;
}

.attention {
background: linear-gradient(to top, darken(#ED4264, $lightChange), #FFEDBC);
text-transform: uppercase;
color: white;
}

@include addPseudoClasses('.attention', red);

.invalid-input {
border-color: red !important;
background-color: pink !important;
}

input[type=text] {
border-radius: $borderRadius !important;
box-shadow: inset 1px 1px 0 black;
padding-left: 20px;
font-weight: 900;
}





The full project-code is on GitHub: https://github.com/mizech/simple-calculator

And in case someone likes to see the code of the second app: https://github.com/mizech/weather-app

If someone has an idea what causes the issue with the blank page then I would really much appreciate it as an answer.

str str
Answer

Just open the app with a browser console and you will see an error message (or open it on Safari on the desktop):

SyntaxError: Unexpected identifier 'item'

That is caused by let item = this.refs.inputElement;. Not all browsers support ES6 just yet. You have to transpile ES6 to ES5 using Babel or Google Traceur.