Build a simple web application using Reactjs

Lets build a simple Conference application in Vue.js. It will basically have following sections :

  1. It will list down all the speakers speaking in the conference
  2. For each session you can rate it out of 5
  3. You can delete the session
  4. You can do multi select and delete multiple sessions at one time
  5. You can also add a new session

Here is how it will look like :

In Reactjs we divide the UI into multiple components. For example this UI can be divided among following components :

  1. Wrapper : This component will represent the whole page.
  2. SessionsList : It will list of all sessions displayed in grid format. It will be sub-component of Wrapper
  3. Session : It will display the information related to a session like its speaker, topic, deleting session, rating it etc. It will be sub-component of SessionsList
  4. AddSessionForm : The form which will be used to add new sessions.
    It will be sub-component of Wrapper
  5. Speaker : Component representing the Speaker’s image, name, and topic. It will be part of Session component
  6. Rating: Component which can be used to rate the session
    It will be part of Session component

Lets start building each component one by one :

Wrapper

class SessionsWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sessions: [
        { id: 100, speaker: 'Uday Ogra', time: '10:00 AM', isChecked: false, topic: 'Integrating modern day Javascript framewroks with ColdFusion', img: 'https://pbs.twimg.com/profile_images/1518734182/uday2_400x400.jpg' },
        {
          id: 101, speaker: 'Suchika Singh', time: '11:00 AM', isChecked: false, topic: 'All about scheduled tasks and using them in ColdFusion', img: 'https://www.adobe.com/content/dam/acom/en/devnet/authors/bio/s/Suchika_Singh.jpg'
        }, {
          id: 102, speaker: 'Pavan Kumar', time: '01:00 PM', isChecked: false, topic: 'Securing your CF applications and using security analyzer tool', img: 'https://www.adobe.com/content/dam/acom/en/devnet/authors/bio/i/Immanuel_noel.jpg'
        }, {
          id: 103, speaker: 'Raj Pandian', time: '01:00 PM', isChecked: false, topic: 'Securing your CF applications and using security analyzer tool', img: 'https://www.adobe.com/content/dam/acom/en/devnet/authors/bio/i/Immanuel_noel.jpg'
        }]
    };

  }

  sessionsChangedEvent(sessions) {
    this.setState({
      sessions: sessions
    }, function () { })

  }

  render() {

    return <div id='app' className='container' >
      <div className='row'>
        <h1>CF Summit Speakers</h1>
        <SessionsList sessions={this.state.sessions} sessionsChangedEvent={this.sessionsChangedEvent.bind(this)} />
      </div>
      <AddSessionForm sessions={this.state.sessions} sessionsChangedEvent={this.sessionsChangedEvent.bind(this)} />

    </div>
  }
}

So we have SessionsWrapper component. In the render function it displays primarily two sub components : SessionsList and AddSessionForm which we will discuss soon. Each of these components are being passed list of sessions (this.state.sessions) and sessionsChangedEvent which will take care of updating the Sessions list whenever a change happens to it like adding a new session or deleting an existing session.

SessionsList

class SessionsList extends React.Component {

  checkSession = (event) => {
    let sessions = this.props.sessions
    sessions.forEach(session => {
      //console.log(event.target.id);
      if (session.id == event.target.id) {
        //console.log(event.target.checked);
        session.isChecked = event.target.checked;
      }
    })
    this.props.sessionsChangedEvent(sessions)

  }

  deleteSession(id) {
    var filtered = this.props.sessions.filter(function (value, index, arr) {

      return value.id != id;

    });

    this.props.sessionsChangedEvent(filtered);

  }


  render() {
    return <div>
      {this.props.sessions.map((session, index) => {
        let className = 'even';
        if (index % 2 == 1)
          className = 'odd';
        className = 'col-md-3 offset-top-1 ' + className
        return <div className={className} key={index}>
          <Session session={session} sessions={this.props.sessions} checkSession={this.checkSession.bind(this)} deleteSession={this.deleteSession.bind(this)}></Session>
        </div>
      })}
    </div>
  }
}

Here in the render method we are iterating over sessions (we got this variable from parent component which is SessionsWrapper via props). We are using if logic to apply conditional styling for alternating sessions. For each session it is displaying Session component which we will discuss next. To this child component it is passing deleteSession function which basically deletes a session from the pre-defined sessions list and checkSession function which basically tells if a given session is checked or not(for mass delete option which we will discuss later).

Both of these methods call sessionsChangedEvent method in the parent component(SessionWrapper) so that parent component can update the Sessions list in state scope. Once parent component updates the sessions list, all the child components will re-render themselves if they were making use of sessions list.

Session

class Session extends React.Component {

  constructor(props) {
    super(props);
  }

  deleteSession(id) {
    this.props.deleteSession(id);
  }

  checkSession(event) {

    this.props.checkSession(event)
  }



  render() {
    let session = this.props.session
    return <div className='portrait'>
      <input type="checkbox" id={session.id} value={session.isChecked} onClick={this.checkSession.bind(this)} />
      <Speaker img={session.img} name={session.speaker} topic={session.topic} time={session.time} />
      <Rating sessionid={session.id} />
      <button className="btn btn-danger" onClick={(e) => this.deleteSession(session.id)}>Delete</button>
    </div>
  }

}

Here in the render method we are first displaying the checkbox which is meant for mass sessions delete functionality. Then we display Speaker component , followed by Rating component and lastly a button for deleting the session.

Speaker

class Speaker extends React.Component {

  render() {
    return <div><img className='speakerImg' src={this.props.img} heigth='100' width='100'></img>
      <div className='speakerName'>{this.props.name}</div>
      <div className='topic'>{this.props.topic}</div><br></br>
      <div className='time'><i>@{this.props.time}</i></div><br></br>
    </div>
  }
}

Speaker component is pretty simple. It displays the image and name of the speaker followed by the topic and the time of the session.

Rating

class Rating extends React.Component {

  constructor(props){
    super(props);
    this.state = {};
  }

  rateSession(id) {
    this.setState({ rating: this.refs.ratingVal.value }, function(){
      console.log(this.state.rating);
    });
  }

  render() {
    const ratings = [{ value: 1, text: '1 star' }, { value: 2, text: '2 star' }, { value: 3, text: '3 star' }, { value: 4, text: '4 star' }, { value: 5, text: '5 star' }];
    const html = <div><select className='dropDown' ref='ratingVal'>
      {ratings.map((rating, index) => {
        return <option className='col-md-3 offset-top-1' key={index} value={rating.value}>
          {rating.text}
        </option>
      })}
    </select>

      <button className="btn btn-secondary" value='Rate'
        onClick={(e) => this.rateSession(this.props.sessionid)}>Rate</button>

      {this.state.rating  &&
        <div className='rateMsg' >You rated <b>{this.state.rating}</b> stars</div>}

      {!this.state.rating  &&
        <div className='rateMsgNot' >You have not rated yet</div>}

    </div>
    return html;
  }
}

In rating component we display 5 types of ratings. Clicking on Rate button will set rating variable in the state scope. If rating variable inside state scope is defined, we will display the current rating given by user else we will tell that rating has not been done yet

AddSessionForm

class AddSessionForm extends React.Component {

  constructor(props) {
    super(props);
    this.state = { showAdvancedSettings: false };

  }
  addSession() {
    let sessions = this.props.sessions;
    sessions.push({ id: this.props.sessions.length + 1, speaker: this.refs.speaker.value, topic: this.refs.topic.value, time: this.refs.time.value });
    this.props.sessionsChangedEvent(sessions);
  }
   deleteMultiSessions() {
    let sessions = this.props.sessions;
   
    var filtered = sessions.filter(function (session, index, arr) {
      return !session.isChecked;

    });

    this.props.sessionsChangedEvent(filtered);

  }

  toggleAdvancedSettings() {
    this.setState({ showAdvancedSettings: !this.state.showAdvancedSettings });
  }
  render() {

    return <div>
      <div className='offset-top-1'>
        <button className="btn btn-danger" onClick={(e) => this.deleteMultiSessions()}>Delete Selected Sessions</button>

        <button className="btn btn-secondary"
          onClick={(e) => this.toggleAdvancedSettings()}>Show/Hide Advanced Settings</button>

      </div>
      {this.state.showAdvancedSettings &&
        <div>
          <h1>Add new Session</h1>
          <form >
            <div className="form-group row">
              <label className="col-sm-2 col-form-label">Enter Speaker's Name</label>
              <div className="col-sm-8">
                <input className="form-control" ref='speaker' />
              </div>
            </div>
            <div className="form-group row">
              <label className="col-sm-2 col-form-label">Enter Topic</label>
              <div className="col-sm-8">
                <textarea ref='topic' className="form-control" ></textarea>
              </div>
            </div>
            <div className="form-group row">
              <label className="col-sm-2 col-form-label">Enter Time</label>
              <div className="col-sm-3">
                <input ref='time' className="form-control" />
              </div>
            </div>
            <button type="button" className="btn btn-secondary" onClick={(e) => this.addSession()}>Add Session</button>
          </form></div>}
    </div>
  }
}

This component is pretty big. First we are displaying button to delete multiple sessions. All sessions who have been checked would be deleted. It calls deleteMultiSession method which basically iterates the sessions and remove all those sessions which have been checked. Filtered list is then passed to parent component so that it can update the state with latest sessions list.

Next is toggleAdvacnedSetting button which toggles the value of variable showAdvancedSettings which is set inside state scope. If this variable is true only then we display the form for adding a new session.

In the add new session form we take speaker’s anme, topic and time of the session. To add we call addSession method which makes use of refs scope to access all the form inputs. It pushes the new session to sessions variable and then calls parent component’s sessionsChangedEvent method to update the sessions list.

Loading the app

ReactDOM.render(
  <SessionsWrapper />,
  document.getElementById('root')
);

This is the last piece of code which loads the SessionsWrapper component and asks React to render it inside element whose id is root

Here is the HTML code which has the root element :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React Demo</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    
	<link rel="stylesheet" type="text/css" href='style.css'>
	<link rel='stylesheet' id='_tk-bootstrap-css'
		href='http://2018.ctbuh.org/wp-content/themes/ctbuh/includes/resources/bootstrap/css/bootstrap.min.css?ver=5.0.2'
		type='text/css' media='all' />
  </head>
  <body>
<div id="root"></div>
<script type="text/babel">
    
  /* 
  ADD REACT CODE HERE 
  */
  
  </script>
    <script src="script.js" type="text/jsx"></script>


  </body>
</html>

That pretty much brings us to the end of the tutorial. You can find the whole code here :
https://github.com/udayogra/reactbasic

Uday Ogra

Connect with me at http://facebook.com/tendulkarogra and lets have some healthy discussion :)

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *