Skip to main content

React: Avoid Conditional In Render

Intro

For the last several posts we have been working on a little weather application with just a couple of nested components.

class App extends React.Component {
// initialize state
state = { lat: null, long: null, errorMessage: "" };

componentDidMount() {
window.navigator.geolocation.getCurrentPosition(
(position) =>
this.setState({
lat: position.coords.latitude,
long: position.coords.longitude,
}),
(err) => {
this.setState({ errorMessage: err.message });
}
);
}

// react requires us to define render
render() {
// if there is an error message and no position data
if (this.state.errorMessage && !this.state.lat) {
return (
<LatLongCard>
<div className="description">Error: {this.state.errorMessage}</div>
</LatLongCard>
);
// if there is no error message and there IS position data
} else if (!this.state.errorMessage && this.state.lat) {
return (
<LatLongCard>
<div className="description">Latitude: {this.state.lat}</div>
<div className="description">Longitude: {this.state.long}</div>
<SeasonDisplay lat={this.state.lat} />
</LatLongCard>
);
// if no error message and no position data
} else {
return <Loading message='fetching location data' />;
}
}
}

ReactDOM.render(<App />, document.querySelector("#root"));

weather widget

React Rule: No Conditional in Render

However so far we have been breaking one of the cardinal rules of React, which is to be placing conditional statements inside of the render function. This is bad for several reasons.

Say for example that no matter which of the three options in the conditional gets chosen, we would like to have a red border always visible around the screen (or a set of navbars…). We would have to create a div for that and repeat it on each of the three conditionals. Repeating code is the enemy.

What we should do instead is break the conditional statement out into a helper method and then reference it inside of the render function. Here we have broken the conditional statement out into a helper function called renderWeatherWidget which cleans up our render function nicely.

class App extends React.Component {
// initialize state
state = { lat: null, long: null, errorMessage: "" };

componentDidMount() {
window.navigator.geolocation.getCurrentPosition(
(position) =>
this.setState({
lat: position.coords.latitude,
long: position.coords.longitude,
}),
(err) => {
this.setState({ errorMessage: err.message });
}
);
}

renderWeatherWidget() {
// if there is an error message and no position data
if (this.state.errorMessage && !this.state.lat) {
return (
<LatLongCard>
<div className="description">Error: {this.state.errorMessage}</div>
</LatLongCard>
);
// if there is no error message and there IS position data
} else if (!this.state.errorMessage && this.state.lat) {
return (
<LatLongCard>
<div className="description">Latitude: {this.state.lat}</div>
<div className="description">Longitude: {this.state.long}</div>
<SeasonDisplay lat={this.state.lat} />
</LatLongCard>
);
// if no error message and no position data
} else {
return <Loading message="fetching location data" />;
}
}

render() {
return (
<div className='red-border'>
{this.renderWeatherWidget()}
</div>
);

}
}

You can imagine that if we had something like a dashboard with several widgets and a navbar the render method would quickly become totally unmanageable if we didn’t break conditionals out into helper methods like this.

Automated Amazon Reports

Automatically download Amazon Seller and Advertising reports to a private database. View beautiful, on demand, exportable performance reports.

bidbear.io