Module 1: New Component

In this module, we will focus on adding our first component to our app.

Step 1. Set up a basic Component

Please follow these steps for component set up:

  1. Inside of index.js, add the following to the top of the file:

    import 'bootstrap/dist/css/bootstrap.min.css';
  2. Right click on your src folder and add new folder called home folder.

  3. Add a Navbar.js file in the home folder.

  4. Create a basic navbar component in that file:

import React, { Component } from 'react'; 
import {
    Navbar,         //1
    NavbarBrand,
} from 'reactstrap';

class SiteBar extends Component {
    constructor(props) {   //2
        super(props);
        this.state = {};
    }

    //3
    render() {
        return (
            <div>
                <Navbar color="faded"  light expand="md">
                    <NavbarBrand href="/">Workout Log</NavbarBrand>
                </Navbar>
            </div>
        );
    }
}

export default SiteBar;

Analysis

Looking at the above code, make sure to note the following:

1. Notice the specific reactstrap imports, we're only grabbing what we need from the file. 2. Review constructors from React Fundamentals and remember that it defines the initial state of the component. 3. Notice we are rendering a div that includes reactstrap components Navbar and NavbarBrand.

App.js

Now let's jump into our App.js so we can see our new component. Remember the first thing we will need to do is import our new component at the top:

import SiteBar from './home/Navbar';

Once you import your new component, call it inside of your render, (meaning in the return() of the render(). Your App.js should look like this now:

import React, { Component } from 'react';
import SiteBar from './home/Navbar';

class App extends Component {

  render() {
    return (
        <div>
          <SiteBar />
        </div>
    );
  }
}

export default App;

Step 2. Handling the Token

As a reminder, in order to have authenticated requests, you need to get a token from the server when you sign up or log in. Then, you'll use that token in all future requests to the server.

In React, the best place to store that token is in a component that has a lot of children, in this case our main parent, App.js. This way, we can pass that token as a prop to all of the child components that need it. Let's first set up the structure to store the token in App.js before dealing with the process of logging in.

In App.js write the following code inside of your class component but above the render:

constructor() {
    super();
    this.state = {
      sessionToken: ''  //1
    }
  }

componentWillMount() {
    const token = localStorage.getItem('token'); //4
    if (token && !this.state.sessionToken) {   //5 
      this.setState({ sessionToken: token });
    }
}
                //2
setSessionState = (token) => {
    localStorage.setItem('token', token); //3
    this.setState({ sessionToken: token });
}

//render method is down here

Analysis

Let's take a look at some notes about the above code block: 1. We're storing our sessionToken in the state, basically the best place to handle storing information in React! 2. We created a function called setSessionState that takes a token in, and then uses that to set the state of sessionToken equal to that token. 3. We're setting the token in the localStorage, so that if the page refreshes we can grab it from the local storage again. Just a reminder: localStorage is an extremely secure place to store things. 4. In componentWillMount we are grabbing the token if it exists from the local storage. 5. Then, we set it in the state if the state is still empty. This would be useful on page refresh, etc. so that the user doesn't have to log into the app upon every visit.

Step 3. Login and Signup Components

We need to add some folders and files. Please follow these steps: 1. Right click on your src folder and add an auth folder. 2. Inside of the auth folder, add the following files. Note that they should have capital names: Auth.js, Login.js, and Signup.js

Auth.js

Go into Auth.js and add the following basic layout:

import React from 'react';
import { Container, Row, Col } from 'reactstrap';
    //1
const Auth = () => {
    return (
        <Container>
            <Row>
                <Col md="6">
                    <div>Signup</div>
                </Col>
                <Col md="6">
                    <div>Login</div>
                </Col>
            </Row>
        </Container>
    )
}
export default Auth;

Not a lot of analysis needed here, but let's note a few things: 1. We are creating a functional component. It has no state, and it will simply pull in the props that will be passed down eventually. 2. Currently, this component is basically going to hold our login and signup forms side by side.

Login.js

Now we need to setup our Login.js. Let's add the following code in that file:

import React, { Component } from "react";
import { Form, FormGroup, Label, Input, Button } from 'reactstrap';

class Login extends Component {
    constructor(props) {
        super(props)
        this.state = {};
    }

    render() {
        return (
            <div>
                <h1>Login</h1>
                <h6>Lorem ipsum dolor sit amet consectetur adipisicing elit. Minus repellat, atque nulla, soluta vero reprehenderit numquam incidunt, rem quaerat quos voluptatum perferendis. Distinctio culpa iste atque blanditiis placeat qui ipsa?</h6>
                <Form>
                    <FormGroup>
                        <Label for="username">Username</Label>
                        <Input id="li_username" type="text" name="username" placeholder="enter username" />
                    </FormGroup>
                    <FormGroup>
                        <Label for="password">Password</Label>
                        <Input id="li_password" type="password" name="password" placeholder="enter password" />
                    </FormGroup>
                </Form>
            </div>
        )
    }
}
export default Login;

Analysis

This is a standard Class Component that comes with state. We need it to be a class component because the state of the form will change as our users enter data. The form will be handling our username and password fields.

A few key items to note: 1. Notice the name property in the Input component calls, "username" and "password". We will be tethering our state to those name properties later on. 2. The id properties start with 'li'. This is our choice/convention for 'log in'. Don't think that it means 'list item'.

Signup.js

Let's add to our Signup.js component:

import React, { Component } from "react";
import { Form, FormGroup, Label, Input, Button } from 'reactstrap';

class Signup extends Component {
    constructor(props) {
        super(props)
        this.state = {};
    }

    render() {
        return (
            <div>
                <h1>Sign Up</h1>
                <h6>Lorem ipsum dolor sit amet consectetur adipisicing elit. Minus repellat, atque nulla, soluta vero reprehenderit numquam incidunt, rem quaerat quos voluptatum perferendis. Distinctio culpa iste atque blanditiis placeat qui ipsa?</h6>
                <Form>
                    <FormGroup>
                        <Label for="username">Username</Label>
                        <Input id="username" type="text" name="username" placeholder="enter username" />
                    </FormGroup>
                    <FormGroup>
                        <Label for="password">Password</Label>
                        <Input id="su_password" type="password" name="password" placeholder="enter password" />
                    </FormGroup>
                </Form>
            </div>
        )
    }
}

export default Signup;

Analysis

Like the Log in component, this is a standard Class Component that comes with state. We need it to be a class component because the state of the form will change as our users enter data. The form will be handling our username and password fields.

A few key items to note: 1. Notice the name property in the Input component calls: "username" and "password". We will be tethering our state to those name properties later on when we want to gather values for signing up a user. 2. The id properties start with 'su'. This is our choice/convention for 'sign up'.

Step 4: Importing our Login/Signup

Now let's see what we are working with by following these steps:

  1. Go ahead and import your two new components into your Auth.js:

    import Signup from './Signup';
    import Login from './Login';
  2. Inside the two columns and the calls for the Signup and Login components:

    const Auth = () => {
     return (
         <Container>
             <Row>
                 <Col md="6">
                     <Signup />
                 </Col>
                 <Col md="6">
                     <Login />
                 </Col>
             </Row>
         </Container>
     )
    }
  3. Go into App.js.

  4. Add an import for Auth.js at the top of the file.

  5. We also need to import our router with a few tools to make routing simpler in the following manner:

import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom';
  1. Then add jsx <Auth /> into your render, as well as surround your <div> tags with <Router>:

    <Router>
     <div>
         <SiteBar />
         <Auth />
     </div>
    </Router>

A little bit of important analysis about Router:

  • Router is what we wrap our application in, so that we can use react-router-dom in our app. Without this we can't route to specific components, or anything within our application. It's very common for Router to be wrapped around the divs in the highest parent component.

  1. Your final code should look like this:

import React, { Component } from "react";
import SiteBar from "./home/Navbar";
import Auth from './auth/Auth';
import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom';

class App extends Component {

  constructor() {
    super();
    this.state = {
      sessionToken: ''  //1
    }
  }

componentWillMount() {
    const token = localStorage.getItem('token'); //4
    if (token && !this.state.sessionToken) {   //5 
      this.setState({ sessionToken: token });
    }
}

setSessionState = (token) => {
    localStorage.setItem('token', token); //3
    this.setState({ sessionToken: token });
}

render() {
    return (
      <Router>
      <div>
          <SiteBar />
          <Auth />
      </div>
     </Router>
    );
  }
}

export default App;

Make sure everything is saved, and then refresh the page. If you run your app with npm start at this point, you should see the following:

Last updated