Coding Journal

Jordan Vidrine

Daily Coding Journal

A Self-taught coder from the Cajun Prairie in rural Louisiana, currently working as a designer for Discourse.

I am always trying to better myself, and do so through learning new skills, trying out new routines, traveling, and pouring energy into hobbies. Since 2014, I have been recording, editing, and producing my own music under the name Skies Speak.

October 3rd - React

Starting the day learning about using forms in React. This is something I haven’t worked with so I am eager to learn how these are supposed to work in this framework.

Forms

HTML form elements work differently than other DOM elements in React. Form elements naturally keep some form of internal state. For example, this form in plaint HTML accepts a single name:

<form>
  <label for="fullname">Full Name:</label>
  <input name="fullname" />
  <button>Add!</button>
</form>

Normally, we wouldn’t know what someone typed into the input field, until the submit event is triggered via the button. It will be convenient to have a JS function that handles the submission of the form, AND has access to the data the user has entered.

This technique is called a controlled component.

Controlled Components

Ok, at this point, I realize I DO know what we are talking about. We are going to be using a function to always keep the state updated to what the user is typing into the form, regardless of if submit has been pressed.

This way we make React the ‘one source of truth’. We keep track of all changing data in the STATE and then it is passed to the appropriate form fields.

This is why the component is referred to as Controlled. React is keeping the state, and passing it into the component to appropriately render. The only issue with this is that each form element that is tied to state causes our forms to get a little long. Each one will need the handleChange function, as well as a reference to this.state.whatevervalue to keep it all controlled.

Handling multiple inputs

In order to set the state appropriately for multiple inputs, our handleChange function will have to know which part of the state to edit, depending on which input was typed in.

In order to do this we will use an ES2015 feature called Computed Property Names.

ex.

let microchip = 1432232113;
let data = {
  [microchip] : "Product One"
}

This is a pretty awesome feature as it allows an easy creation of keys as variables in objects.

So, instead of making a separate handleChange for each input, we can make a generic function for multiple inputs. To do this, we add the HTML name attribute to each JSX input element and let the handler function decide the right key in state to update based on event.target.name.

handleChange(event) {
  this.setState({
    [event.target.name] : event.target.value
  })
}

Passing Data Up to a Parent Component

In React, we normally have a downward data flow. “Smart” parent components with simpler child components. However, forms need a lot of state to work correctly, so we will make them into their own component. Here is some code to illustrate how we would do this.

class ShopingList extends Component {
  constructor(props) {
    super(props)
    this.state = {
      items: [
        {name: "milk", qty: 2},
        {name: "bread", qty: 3}
      ]
    };
    this.addItem = this.addItem.bind(this)
  }
  addItem(item){
    this.setState(state => ({
      items: [...state.items, item]
    }));
  }
  render() {
    return (
      <div>
      <ShoppingListForm addItem={this.addItem}/>
      </div>
    )
  }
}

class ShoppingListForm extends Component {
  constructor(props) {
    super(props)
    this.state = {name:"", qty:""}
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }
  handleChange(evt){
    this.setState({
      [evt.target.name] : evt.target.value
    })
  }
  handleSubmit(evt) {
    evt.preventDefault()
    this.props.addItem(this.state)
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label htmlFor="name">Name: </label>
        <input
        id="name"
        name="name"
        value={this.state.name}
        onChange={this.state.handleChange}
        />
        <label htmlFor="qty">Qty: </label>
        <input
        id="qty"
        name="qty"
        value={this.state.qty}
        onChange={this.state.handleChange}
        />
        <buttom>Add Item</button>
      </form>
    )
  }
}

What we are essentially doing here, is passing the state of the child component, ShoppingListForm up to the parent form, by calling a function with the child’s state as its argument from the parent into the child’s props.

Creating Keys with the UUID Library

Since React wants us to use keys for listed out items, it is nice to have a uniquely generated key for each of those items. We can do this by using the UUID Library. It is pretty straightforward in its use.

When creating items and adding them to state, we can do this:

this.setState(state => {
  users: [...this.state.users, {name, email, id: uuid()}]
})

To use the id as a key, in a map call we would do something like this:

<User name={user.name} email={user.email} key={user.id} />

Exercise: Box Project

Part 1 - Color Box Maker Create a new React application, which contains the following components:

When each Box component is displayed, add a button with the text of of “X” next to each Box. When this button is clicked, remove that specific box. This will require you to pass a function down as props - the button should not be a separate component, it should be included in the Box component.

Here was my solution to this exercise.


function App() {
  return (
    <div className="App">
      <BoxList />
    </div>
  );
}

class BoxList extends Component {
  constructor(props) {
    super(props)
    this.state = {
      boxes: []
    }
    this.remove = this.remove.bind(this)
    this.create = this.create.bind(this)
  }

  remove(id) {
    let boxes = this.state.boxes.filter(box => box.id !== id)
    this.setState(state => {
      return {
        boxes
      }
    })
  }

  create(box) {
    box.id = uuid()
    this.setState(state => {
      return {
        boxes: [...this.state.boxes, box]
      }
    })
  }

  render() {

    let boxes = this.state.boxes.map(box => {
      return (
        <Box h={box.h+'px'} w={box.w+'px'} color={box.color} key={box.id} id={box.id} onClick={this.remove}/>
      )
    })
    return (
      <div className="BoxList">
        <h1>Box list</h1>
        <NewBoxForm onSubmit={this.create}/>
        {boxes}
      </div>
    )
  }
}

class Box extends Component {
  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.props.onClick(this.props.id)
  }

  render() {
    let style = {
      backgroundColor: this.props.color,
      width: this.props.w,
      height: this.props.h
    };

    return (
      <div className="Box" id={this.props.id}>
        <div className="Box-dipslay" style={style}>
        </div>
        <button onClick={this.handleClick}>Remove Box</button>
      </div>
    )
  }
}

class NewBoxForm extends Component {
  constructor(props) {
    super(props)
    this.state = {
      w: '',
      h: '',
      color: '',
    }
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleChange(evt) {
    this.setState({[evt.target.name] : evt.target.value })
  }

  handleSubmit(evt) {
    evt.preventDefault();
    this.props.onSubmit(this.state)
  }

  render() {
    return (
      <div className="NewBoxForm">
        <form onSubmit={this.handleSubmit}>
          <label htmlFor="width">Width </label>
          <input id="width" name="w" onChange={this.handleChange}/>
          <label htmlFor="height">Height </label>
          <input id="height" name="h" onChange={this.handleChange}/>
          <label htmlFor="color">Color </label>
          <input id="color" name="color" onChange={this.handleChange}/>
          <button>Create Box</button>
        </form>
      </div>
    )
  }
}

This was a fun exercise in implementing the ability for a child component to have its own state depending on what was typed into the form. I love using a computed property name in the handleChange function and knowing how useful this ability is.

Back to blog...