3
\$\begingroup\$

The exercise is part of a React course in which I'm currently enrolled.

Description:

Exercise-description

The way it shall look on desktop-screen:

The way it shall look on desktop-screen

How it shall look on mobile:

How it shall look on mobile

Here's my solution:

HTML

<div id="display"></div>

JSX

// Manager bundles the single components together.
var React = require('react');
var ReactDOM = require('react-dom');
var PanelWithoutHeading = require('./components/PanelWithoutHeading.jsx');
var PanelCentered = require('./components/PanelCentered.jsx');
var PanelColoredHeading = require('./components/PanelColoredHeading.jsx');
var PanelLarge = require('./components/PanelLarge.jsx');

var largePanelVals = [
  {
    headline: 15080,
    text: 'Shot Views'
  },
  {
    headline: 12000,
    text: 'Likes'
  },
  {
    headline: 5100,
    text: 'Comments'
  }
];

var PanelManager = React.createClass({
    render: function() {
        return (
            <div className="container">
              <div className="row">
                <PanelWithoutHeading headline="20" text="New followers added this month" />
                <PanelWithoutHeading headline="$ 1250" text="Average Monthly Income" />
                <PanelWithoutHeading headline="$ 13865" text="Yearly Income Goal" />
                <PanelCentered headline="18 deg" text="Paris" backgroundColor="orange" />
              </div>
              <div className="row">
                <PanelLarge vals={ largePanelVals } backgroundColor="violet" />
                <PanelColoredHeading headingColor="blue" description="New visitors" message="1.5k" />
                <PanelColoredHeading headingColor="violet" description="Bounce Rate" message="50%" />
              </div>
              <div className="row">
                <PanelLarge vals={ largePanelVals } backgroundColor="violet" />
                <PanelColoredHeading headingColor="red" description="Searches" message="28%" />
                <PanelColoredHeading headingColor="green" description="Traffic" message="140.5 kb" />
              </div>
            </div>
        );
    }
});

// Render the bundle into HTML.
ReactDOM.render(<PanelManager />, document.getElementById('display'));

// -- THE COMPONENTS ----------------------------

// 1. Component
var React = require('react');

var PanelCentered = React.createClass({
  render: function() {
     var divStyle = {
      'marginTop': '10px'
    } ;

    var panelStyles = {
      'background': this.props.backgroundColor,
      'textAlign': 'center',
      'color': 'white',
      'minHeight': '100px'
    };

    var h3Styles = {
      fontSize: '36px'  
    };

    return (
      <div className="col-md-3" style={ divStyle }>
        <div className="panel panel-default" style={ panelStyles }>
          <div className="panel-body">
            <h3 style={ h3Styles } >{ this.props.headline }</h3>
            <p>{ this.props.text }</p>
          </div>
        </div>
      </div>
    );
  }
});

module.exports = PanelCentered;

// 2. Component
var React = require('react');

var PanelColoredHeading = React.createClass({
  render: function() {
    var divStyle = {
      'marginTop': '10px',
      'minHeight': '100px'
    } ;

    var panelHeadingStyle = {
      'color': 'white',
      'background': this.props.headingColor
    };

    var messageStyle = {
      'fontSize': '1.2em',
      'fontWeight': 800
    };

    return (
      <div className="col-md-3 col-sm-12" style={ divStyle }>
        <div className="panel panel-default">
          <div style={ panelHeadingStyle }  className="panel-heading">
            <p>{ this.props.description }</p>
            <p style={ messageStyle }>{ this.props.message }</p>
          </div>
          <div className="panel-body"></div>
        </div>
      </div>
    );
  }
});

module.exports = PanelColoredHeading;

// 3. Component
var React = require('react');

var PanelWithoutHeading = React.createClass({
  render: function() {
    var divStyle = {
      'marginTop': '10px'
    } ;

    var panelStyle = {
      'height': '130px',
      'minHeight': '100px'
    }
    return (
      <div className="col-md-3" style={ divStyle }>
        <div style={ panelStyle } className="panel panel-default">
          <div className="panel-body">
            <h3>{ this.props.headline }</h3>
            <p>{ this.props.text }</p>
          </div>
        </div>
      </div>
    );
  }
});

module.exports = PanelWithoutHeading;

// 4. Component
var React = require('react');

var PanelLargePart = React.createClass({
  render: function() {
    var panelStyle = {
      'border': 0,
      'minHeight': '130px'
    };

    var bigFont = {
      'fontWeight': 800,
      'fontSize': '1.3em',
      'paddingTop': '15px'
    };

    var divStyle = {
      'paddingLeft': this.props.paddingLeft,
      'paddingRight': this.props.paddingRight
    }

    return (
      <div className="col-xs-4 lower-part" style={ divStyle }>
        <div className="panel panel-default" style={ panelStyle }>
          <div className="panel-body" >
            <p style={ bigFont }>{ this.props.headline }</p>
            <p>{ this.props.text }</p>
          </div>
        </div>
      </div>
    );
  }
});
var PanelLarge = React.createClass({ 
  render: function() {
    var divStyle = {
      'marginTop': '10px'
    } ;

    var topRow = {
      'height': '120px',      
      'background': this.props.backgroundColor,
      'marginLeft': '0px',
      'marginRight': '0px',
      'minHeight': '130px'
    }

    var lastElement = this.props.vals.length - 1;

    var panels = this.props.vals.map(function(val, i) {
      var leftPadding;
      var rightPadding;
      // First panel (i === 0) gets NO left-padding
      !i ? leftPadding = '15px' : leftPadding = '0';

      i === lastElement ? rightPadding = '15px' : rightPadding = '0';

      return <PanelLargePart paddingLeft={ leftPadding }
                             paddingRight={ rightPadding }
                             headline={ val.headline }
                             text={ val.text } 
                             key={ i }/>
    });

    return (
      <div className="col-md-9 col-sm-12" style={ divStyle }>
        <div className="row" style={ topRow }>
          <div className="col-xs-12"></div>
        </div>
        <div className="row">
          { panels }
        </div>
      </div>
    ) 
  }
});

module.exports = PanelLarge;

Live demo with compiled JSX-code here.

While coding I've realized that I'm still very much a React beginner. Any hints and tips are welcomed. The same goes for the Bootstrap usage.

\$\endgroup\$
5
+100
\$\begingroup\$

Move variables out of render

All the variables you are storing are sitting in the render method of the respective component. This means that the variables are constantly created and destroyed.

It would be better to either:

  • Set them as properties of the object you are passing into React.createClass()
  • Write the values inline with the returned elements.

Modify special loop cases separately

In this loop:

var lastElement = this.props.vals.length - 1;

var panels = this.props.vals.map(function(val, i) {
  var leftPadding;
  var rightPadding;
  // First panel (i === 0) gets NO left-padding
  !i ? leftPadding = '15px' : leftPadding = '0';

  i === lastElement ? rightPadding = '15px' : rightPadding = '0';

  return <PanelLargePart paddingLeft={ leftPadding }
                         paddingRight={ rightPadding }
                         headline={ val.headline }
                         text={ val.text } 
                         key={ i }/>
});

The special cases are the first and last element: you've written two conditionals and are storing extra data just so you can handle these two separately from the rest.

Rather than that, it would be a lot simpler and a lot cleaner in the loop if you instead modified the elements after the loop:

var panels = this.props.vals.map(function(val, i) {
    return <PanelLargePart paddingLeft={ leftPadding }
                         paddingRight={ rightPadding }
                         headline={ val.headline }
                         text={ val.text } 
                         key={ i }/>
});
panels[0].props.paddingLeft = '0';
panels[panels.length - 1].paddingRight = '15px';

Stateless Functional Components

None of your components hold a state. Therefore, it is better practice to write them in the form of a stateless functional component:

function MyComponent(props) {
    return <my-tags/>
}

ES6

Small, side recommendation: learn ES6 and use it with React. React (and libraries like Flux and Redux) work a lot better, cleaner, and easier with ES6, e.g., creating classes is more natural in ES6 since you use the actual class system.

Also, things are just starting to move away from ES5 anyway, so it would be good to get comfortable with ES6.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.