Learning React - Week 2

This is the second week in my 30 days, 30-minute challenge to learn React via the brilliant course from Wes Bos React for Beginners.

You can catch the first weeks round up here.

Please note: these posts are in no way a replacement for the course. They are my notes as I progress through the 30 days. I 100% recommend purchasing the course or following Wes Bos on Twitter if you're interested in React.

Day 8: Stateless Functional Components

True React components are complex beings. They have a whole bunch of inherited features like lifecycle methods along with other additional methods that we create.

Sometimes we simply don't need this complexity. For instance, our Header component is only used to render HTML to the DOM. It doesn't need to be anything more than an arrow function.

This means we can convert it from a full React Component into a Stateless Functional Component:
Converting a React Component into a Functional Stateless Component

Rule of thumb:
if( component only uses render method ){  
convert it to a stateless functional component  
}

Further Reading: This was only a short video so I was able to do some more reading about Stateless Functional Components for the rest of the 30-minutes. Here are some of the good resources I found:

Today the app looks like:

App on Day 8 of the React for Beginners Course

Note: There were no visual changes from yesterday

[Video 8: Stateless Functional Components]

Day 9: Using React Router

Today we explored the React Router tool. It doesn't come as part of the React package but it is the industry standard for implementing routing within React applications.

Our application routing will be handled by a simple component that has some if/else style logic built in. It calls the Match and Miss from React Router to handle the heavy lifting.

Import { BrowserRouter, Match, Miss } from 'react-router';

const Root = () => {  
  return(
    <BrowserRouter>
      <div>
        <Match exactly pattern="/" component={StorePicker} />
        <Match pattern="/store/:storeId" component={App} />
        <Miss component={NotFound} />
      </div>
    </BrowserRouter>
  )
}

Note: This is using an outdated version of React Router. The latest verison would look more like:

Import { Switch, Route } from 'react-router-dom';

const Root = () => {  
  return(
    <Switch>
        <Route exact path="/" component={StorePicker} />
        <Route path="/store/:storeId" component={App} />
        <Route component={NotFound} />
    </Switch>
  )
}

The results can be seen below. The only other task from todays workshop was to create a NotFound component that can display as a sudo 404 page.

Today the app looks like:

App on Day 9 of the React for Beginners Course

[Video 9: Routing with React Router]

Day 10: Helper Functions

Today was a short and sharp lesson about helper functions. These aren't React specific but is something that Wes Bos chooses to put into his Javascript applications.

If a function is going to be used throughout the app but isn't important/big enough to warrant creating a module for it then putting it in the helper.js file is a good idea.

The project files were generated with a few helper functions that allow us to generate random Store names and format the price to display in a currency format nicely.

Using these functions is as easy as importing the function & then calling it:

import { getFunName } from '../helpers';  
...
<input type="text" required placeholder="Store Name" defaultValue={ getFunName() } />  
...
Today the app looks like:

App on Day 10 of the React for Beginners Course

[Video 10: Helper and Utility Functions]

Day 11: React Events

A couple of things of note from today's lesson:

  • React events are handled via the SyntheticEvent
  • React events are done in line.
  • To get data out of an input we need to use a function ref.
  • render() is a method that is inherently bound to the component.
  • When adding an additional/custom method do a component you need to explicitly bind it to the component so that we can use this within it.

There are a few ways that you can bind custom methods to the component:

You can reference them within the constructor() e.g:

class StorePicker extends React.Component {  
  constructor(){
    super();
    this.goToStore = this.goToStore.bind(this);
  }

  goToStore() {
    //Custom method.
  }

  render() {
    //Standard method
  }
}

You can bind the method when it is being called by the onSubmit event handler. e.g:

render() {  
    return(
      <form className="form" onSubmit={this.goToStore.bind(this)}>
        <input type="text" ref={(input) => {this.storeInput = input}}/>
        <button type="submit">Submit</button>
      </form>
    )
  }

You can run an arrow function when the method is being called by the onSubmit event handler. e.g:

render() {  
    return(
      <form className="form" onSubmit={(e) => this.goToStore(e)}>
        <input type="text" ref={(input) => {this.storeInput = input}}/>
        <button type="submit">Submit</button>
      </form>
    )
  }

We didn't do to many app changes today but we put a console.log() into the event handler so you can see the refs being passed through.

Note: This lesson sparked a lengthy discussion with my development team. Whilst, traditionally the constructor was used to initialise state, however, with the changes in JS we are able to initialise state directly as a class property. This reduces noise in the code as well as increases the performance. Added bonus: when using create-react-app there is no need to worry about transpiling your code - it is already built in. You can read more about this here in React Components and Class Properties by Michal Zalecki.

Today the app looks like:

App on Day 11 of the React for Beginners Course

[Video 11: Working with React Events]

Day 12:

Today we are finishing off the GoToStore() method. We are already receiving in the data that we want to work with (from the input ref) and now we need to action that with a redirect.

To do this we are using the transitionTo method made available to us by React Router.

Because of the one-way data flow of React, we need to surface the router from the parent using contextTypes. This will make it available to our component.

This is done by adding the following below our component on StorePicker.js:

StorePicker.contextTypes = {  
  router: React.PropTypes.object
}

Now that the router object is available to us all we need to do is call the transitionTo() method in our goToStore():

goToStore(event){  
    event.preventDefault();
    const storeId = this.storeInput.value
    this.context.router.transitionTo(`/store/${storeId}`)
  }
Today the app looks like:

App on Day 12 of the React for Beginners Course

[Video 12: All About React Router]

Day 13: Introduction to State

The video for today is titled 'Understanding State'. I'm going to dial that back and instead reference it as 'An Introduction to State'.

Wes does mention that this is one of the videos that you should come back and watch on a regular basis until this concept has cemented itself for you.

Below are my notes from the video:

  • You store all of the application data within this master object called 'state'. Then if you want to change the page then you edit the 'state' and you let React handle the HTML for you.
  • You edit the data. React edits the HTML for you.
  • This is so powerful because once you change some of the data within the state object it is updated everywhere that state is called within your application. No need to worry about each implementation.
  • React needs to know the initial state of the component. In ES6 components this is done within the constructor method by setting this.state = {//state}.
  • When updating your state you should take a copy of your current state, then update your state. This is done for performance and removing race conditions. eg.
//Make a copy of the current state
const fishes = {...this.state.fishes};  
//set time stamp
const timestamp = Date.now();  
fishes[`fish-${timestamp}`] = fish;  
//set state
this.setState({  fishes });  
You can call a function from a child component via props.  
e.g. in App.js:  
<Inventory addFish={this.addFish} />  
then in Inventory.js we can pass this down via props:  
<AddFishFor addFish={this.props.addFish} />  

I'm not 100% across the intricacies of state but I'm going to leave it there for today. We will be going over this again in other videos.

Today the app looks like:

App on Day 13 of the React for Beginners Course

[Video 13: Understanding State]

Day 14:

Today we are focusing on putting a Load Sample Fishes button onto the page. This is handy for quickly inserting some dummy data into the app so we can play around with the display of data in the next lesson. It also gives us a run through of loading state via onClick().

ToDo List:

  • Create a button at the bottom of the Inventory Panel.
  • Have the onClick() call a function (loadSamples()) that loads the object in sample-fishes.js into the state.

Remember: State is on parent component App so this is where the function needs to be. We need to pass this down to the child component via props (just like we did yesterday).

Today the app looks like:

App on Day 14 of the React for Beginners Course

[Video 14: Loading data into state onClick]


Read more in this series: Week 1, Week 3, and Week 4 Or get the React for Beginners Course for yourself.