DEV Community

aurel kurtula
aurel kurtula

Posted on

Introduction to React

There are many ways to start a react project. If you are confident with the terminal and npm/yarn, you'll just need to globally install create-react-app package and then use it to create your react project like so:

create-react-app todo-app
Enter fullscreen mode Exit fullscreen mode

However, for those of you that aren't comfortable with that then you might like to play with codesandbox, simply select react and we are ready to go. That's what I am doing, so follow along there.

In ./index.js we have the following code, which will not change through out this basic tutorial

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

We are importing two packages: react and react-dom. As it can be clearly seen, render is one of the methods react-dom provides. It takes the component App and renders it in the browser, within a node with the id of root

root is located inside index.html

Creating the first component

In line 3 we are importing an App component.

It doesn't exist yet, so lets create ./App.js and add the following code

import React, { Component } from "react";
import "./style.css";
class App extends Component {
  render() {
    return (
      <div className="wrap">
        <h2>Simply todo List</h2>
        <form>
          <input type="text" />
        </form>
        <ul>
          <li>Get Milk <span>x</span></li>
        </ul>
      </div>
    );
  }
}
export default App; 
Enter fullscreen mode Exit fullscreen mode

App is a simple class which extends from react's Component parent class. Doing so, it gets methods such as render, used to return JSX, which, judging from the above, it's simple html - but has extended functionality which will see later.

Finally, note, how we can import regular css directly within the component, which ideally gives us the power to fully modularise each component.

Result so far

So far we have created a simple form and an unordered list with one item in it. The end result would be something like this

Working with State

The content returned from our App component is just static html, not very useful. However, react class components have the ability to create local state, which would make the rendered JSX a lot more dynamic. Let's change the App component to make use of the local state.

Initial state is set within the class constructor and accessible throughout all the class methods

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      title: 'simple Todo List',
      items: [
        'Get milk',
        'Boil water',
        'Bake tea'
      ]
    }
  }
  ...
Enter fullscreen mode Exit fullscreen mode

this.state takes an object, the contents of which can be anything we want. So we specified a title and an array of item's. The constructor takes props as an argument and also super(props) must be called in order for our App class to inherit data (the props object) from the parent class, otherwise known as a superclass.

Now let's edit the JSX to instead render the state data where appropriate

  render() {
    return (
      <div className="wrap">
        <h2>{this.state.title}</h2>
        <form>
          <input type="text" />
        </form>
        <ul>
            {
              this.state.items.map( (item,id)=>
                <li key={id}>{item}</li>)
            }
        </ul>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Note how within the curly braces we are able to run pure JavaScript to loop through the items array in the state.

Two when things there: this.state get's the state object we specified earlier. And, the use of unique key inside the li tag is required by reach every time we iterate through a list, this so that Reach can pinpoint where changes happen and alter the DOM faster.

Modifying the state through user actions

We are now able to manipulate the state based on user input.

The form we render above has two possible actions. We can bind an onChange event in the input field and an onSubmit event on the actual form.

class App extends Component {
  ....
  render() {
    return (
      <div className="wrap">
        ..
        <form onSubmit={this.submitItem}>
          <input type="text" onChange={this.inputChanged} />
        </form>
        ..
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Above we are referring to two methods which don't exist yet. Let's create them

class App extends Component {
  ...
  submitItem(e){
    e.preventDefault();
    console.log('Form Submited')
  }
  inputChanged(e){
     console.log(e.target.value)
  }
  ...
}
Enter fullscreen mode Exit fullscreen mode

With those in place, we will get the value printed in the console every time we enter something in the input field and get the message Form Submitted every time we would press enter in the form.

But that's not very useful. We ideally want to change the state when those events are triggered. To change the state we would run setState method. And it would look something like this.setState(). However, if we consoled this in any of the above methods, it would return null since this doesn't refer to anything inside inputChanged or submitItem. We need to bind these methods to the class. There are two ways to do this. We can bind these methods in the constructor, like so:

  constructor(props){
    super(props)
    this.submitItem = this.submitItem.bind(this)
    this.inputChanged = this.inputChanged.bind(this)
    ...
  }
Enter fullscreen mode Exit fullscreen mode

Or we can create the binding as we use the methods.

...
<form onSubmit={this.submitItem.bind(this)}>
  <input type="text" onChange={this.inputChanged.bind(this)} />
</form>
...
Enter fullscreen mode Exit fullscreen mode

Both work the same way. Clearly, adding all the binding in the constructor gives us a level of organisation which could be useful in large projects.

Now, this inside our two methods refers to the component itself, hence, this.state get's the state object we want to alter.

Lets change the state on submit

Keep in mind the state that we are working with. We have already define it in the constructor:

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      title: 'simple Todo List',
      items: [
        'Get milk',
        'Boil water',
        'Bake tea'
      ]
    }
  }
  ...
Enter fullscreen mode Exit fullscreen mode

When the form is submitted, we would like to modify the items array above. Let's do that, then talk about what's going on

submitItem(e){
  e.preventDefault();
  let items = this.state.items;
  items.push(e.target[0].value)
  this.setState({
    items
  })
}
Enter fullscreen mode Exit fullscreen mode

First line, we just prevent the form from acting in it's default way, in short, we prevent it's default behaviour.

Secondly we get the part of the state we will modify. this.state gives us the state object. Then on line three we push the form value to the items array, and finally we reset the state where this.state.items would include the new content we pushed.

By default the component will re-render causing the render() method to loop through the new array and display the changes.

Lets change the state on change

Back to the form, we have another method which will be triggered every time users modify the input field

...
<form onSubmit={this.submitItem.bind(this)}>
  <input type="text" onChange={this.inputChanged.bind(this)} />
</form>
...
Enter fullscreen mode Exit fullscreen mode

Let's add a property to our state object when that input change happens

inputChanged(e){
  this.setState({
    ValuePlaceholder: e.target.value
  })   
}
Enter fullscreen mode Exit fullscreen mode

Which in turn can be accessed inside the submitItem method, where the way we get the input value can change from

submitItem(e){
  ...
  items.push(e.target[0].value)
  ...
}
Enter fullscreen mode Exit fullscreen mode

To just grabbing the value from the state

submitItem(e){
...
items.push(this.state.ValuePlaceholder)
...
}
Enter fullscreen mode Exit fullscreen mode




Conclusion

That's the basics of how to create a simple todo app in react.

As I already mentioned I created this project using codesandbox and it was a fantastic experience, The editor is fantastic and the setup is amazingly simple. Especially for beginners that aren't comfortable with the terminal.

It also gave me the ability to push this project into github, so feel free to check that repository but also of course, go checkout the demo, at codesandbox

Top comments (3)

Collapse
 
olivermensahdev profile image
Oliver Mensah

Nice piece. Instead of using the bind can you also try using Public Class Fields. They allow you to add instance properties to the class definition with the assignment operator (=).

Collapse
 
aurelkurtula profile image
aurel kurtula

Thanks for the suggestion.

Just so that we are on the same page, you are talking about something like this right?

class App extends Component {
  state = { title: 'something' }
  myClick=()=>{
    this.setState({title: 'Title changed'})
  }
  render() {
    return (
      <div className="wrap">
        <h2>{this.state.title}</h2>
        <button onClick={this.myClick}>clickme</button>
      </div>
    )
  }
}

It does work and I like it.

Thanks again

Collapse
 
olivermensahdev profile image
Oliver Mensah

Welcome.