Let’s create a simple form where all it does is take the submission and displays it.
Yes it sounds simple but there is a lot going on where it can get confusing. But once you get the basics down then everything else that has to do with a form is just an extension of this.
Let’s get started by creating a new react app, cleaning out the template code so we are left with just a blank page.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import './App.css'; | |
class App extends Component { | |
render() { | |
return ( | |
<div className="App"> | |
</div> | |
); | |
} | |
} | |
export default App; |
Next let’s create the form component
Things to remember when creating a component
- Always import react
- Your class should have a render function and a return function.
- Everything inside the return function should be inside a div or section or something or it will cause an error.
- Don’t forget to export the class.
With just a simple h1 our form component looks like this.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
class Form extends Component { | |
render() { | |
return( | |
<div className="Form"> | |
<h1>Form goes here</h1> | |
</div> | |
); | |
} | |
} | |
export default Form; |
We have our simple shell. Before we do any more coding let’s think this out and make steps to follow.
- The user will fill in the text field.
- The user will hit submit and the text will be displayed on the page
- The text field will clear itself out and the user can do this again.
This part was simple enough as this is what the user sees but there is more happening on the back end and this is what we have to code in.
- We need an array that will hold our data : STATE to create
- The data in the array needs to be displayed on a separate line : PROPS to pass down
- Add the form with 1 input field and 1 button
- Capture the text input value: STATE
- Change the value of state with an event listener.
- Add the new item to the array
- Clear the input field
- Bonus: Don’t allow an empty field to be passed in.
This might seem like a lot but in reality it’s not because we broke down our problem into such small steps that we can get each one done in a few minutes.
The thing about coding is that the biggest challenge isn’t the coding it is knowing what to code and if you spend the time before hand to break down the problem, now we just have to worry about the syntax of the language.
Create an array
I am using an array in this example but in the real world outside of learning we would be using a database.
This array is to be modified therefor it should be inside of the state, let’s create the state with our array inside. Remember that our state has to be inside a constructor that uses props. The other thing is that state expects an object so our array has to be inside of an object. It will look like this. Notice how I used some dummy text and that is just to make sure that we have some data to work with on the next step.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Form from './components/Form' | |
import './App.css'; | |
class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
formItems: ['one', 'two', 'three'] | |
} | |
} | |
render() { | |
return ( | |
<div className="App"> | |
< Form /> | |
</div> | |
); | |
} | |
} | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
class Form extends Component { | |
render() { | |
return( | |
<div className="Form"> | |
<h1>Form goes here</h1> | |
</div> | |
); | |
} | |
} | |
export default Form; |
Display data in array
In React, it’s very common to see items iterated through an array with the .map() method, so we will use that here to display each item from our array. Our method is going to look like this:
{ this.state.formItems.map( (element, index) =>
<Form key={ index } />
)}
In React each list item needs to have an individual key attribute so we use the index of the array. This way we know that each item has an individual key value.
Somehow we need to get the array information from the app file to our form element and we use props for this. Just as a reminder props are made to be passed down from a parent element (app in this case) to it’s child components (form). We are passing down the items in the array. We are just going to add this to the information in our
<Form key={index} formElement={element} />
Now in our form element we can access those props with the this.props object and we can render each item in our Form component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Form from './components/Form' | |
import './App.css'; | |
class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
formItems: ['one', 'two', 'three'] | |
} | |
} | |
render() { | |
return ( | |
<div className="App"> | |
<ul> | |
{this.state.formItems.map( (element, index) => | |
<Form | |
key={index} | |
formElement={element} | |
/> | |
)} | |
</ul> | |
</div> | |
); | |
} | |
} | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
class Form extends Component { | |
render() { | |
return( | |
<div className="Form"> | |
<li> {this.props.formElement} </li> | |
</div> | |
); | |
} | |
} | |
export default Form; |
Add the form
The form itself is no different than any other form you have ever created.
<form>
<input type=“text” />
<input type=“submit” />
</form>
The app can go below the text we are displaying so that the user can read through the list before submitting a new item.
Capture the text input value
This is where al the complications happen!
We have to put what the user has typed into a variable so that in the next step we can push it into the array.
We don’t want anything to happen until the user hits the submit button. Lucky for us there is onSubmit attribute that we can add to the form tag. the value will be an arrow function.
<form onSubmit={ (e) => this.handleSubmit(e) }>
In this example e is short for event, but it could be anything you want to name it, it is just common practice to use the letter e.
We are calling the handleSubmit(e) function but it doesn’t exist yet so on top of the file below the component(props) we can create our function.
We are going to call preventDefault to prevent the page from reloading when the submit button is pressed.
handleSubmit(e) {
e.preventDefault();
}
If you wanted to test it to see if it’s actually working we could add a console.log() and check the console.
We don’t need our dummy text in our array so we can delete it leave it blank. After our array we can create a variable to hold the user’s input.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Form from './components/Form' | |
import './App.css'; | |
class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
formItems: [], | |
newFormElement: '' | |
} | |
} | |
handleSubmit(e) { | |
e.preventDefault(); | |
} | |
render() { | |
return ( | |
<div className="App"> | |
<ul> | |
{this.state.formItems.map( (element, index) => | |
<Form | |
key={index} | |
formElement={element} | |
/> | |
)} | |
</ul> | |
<form onSubmit={(e) => this.handleSubmit(e)}> | |
<input type="text" value={this.state.newFormElement} /> | |
<input type="submit" /> | |
</form> | |
</div> | |
); | |
} | |
} | |
export default App; |
The last change you will see is that we set the value of the text element into our variable.
Add an event listener
If you run the app now and enter a word nothing is going to happen. All that work for nothing, well we are putting the information in our variable but we need to change the value in state so that it renders on the screen.
There is an event listener that listens for changes called onChange we will then use it to call a new function titles handleChange.
Just like before the handleChange function doesn’t exist so we will create it. This new function will set the state of newFormElement to whatever was stored in the value field.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Form from './components/Form' | |
import './App.css'; | |
class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
formItems: ['one', 'two', 'three'], | |
newFormElement: '' | |
} | |
} | |
handleSubmit(e) { | |
e.preventDefault(); | |
} | |
handleChange(e) { | |
this.setState({newFormElement: e.target.value}) | |
} | |
render() { | |
return ( | |
<div className="App"> | |
<ul> | |
{this.state.formItems.map( (element, index) => | |
<Form | |
key={index} | |
formElement={element} | |
/> | |
)} | |
</ul> | |
<form onSubmit={(e) => this.handleSubmit(e)}> | |
<input type="text" | |
value={this.state.newFormElement} | |
onChange={ (e) => this.handleChange(e)} | |
/> | |
<input type="submit" /> | |
</form> | |
</div> | |
); | |
} | |
} | |
export default App; |
Add the new item to the array
Now we just have to add the new item to the array. You would think that it would be as easy as to use the push method. But react doesn’t want us to change state directly as errors can happen.
We will use our handleSubmit function to add the new item.
handleSubmit(e) {
e.preventDefault();
this.setState({formItems: […this.state.formItems, this.state.newFormElement] });
}
It’s almost like if we created a new array that contains the previous elements plus the new one.
Clear the input field
It is not clearing the input field after the item is passed to the array. This is a quick fis that can be accomplished by changing the state of the newFormElement varible by assigning it to ‘ ‘.
handleSubmit(e) {
e.preventDefault();
this.setState({formItems: […this.state.formItems, this.state.newFormElement], newFormElement: ” });
}
Bonus: Don’t allow an empty field to be passed in.
Before we add the item to the array we can check to see if it’s empty and if it is then we exit the function by using the keyword return.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Form from './components/Form' | |
import './App.css'; | |
class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
formItems: [], | |
newFormElement: '' | |
} | |
} | |
handleChange(e) { | |
this.setState({newFormElement: e.target.value}) | |
} | |
handleSubmit(e) { | |
e.preventDefault(); | |
if(!this.state.newFormElement) {return} | |
this.setState({formItems: […this.state.formItems, this.state.newFormElement], newFormElement: '' }); | |
} | |
render() { | |
return ( | |
<div className="App"> | |
<ul> | |
{this.state.formItems.map( (element, index) => | |
<Form | |
key={index} | |
formElement={element} | |
/> | |
)} | |
</ul> | |
<form onSubmit={(e) => this.handleSubmit(e)}> | |
<input type="text" | |
value={this.state.newFormElement} | |
onChange={ (e) => this.handleChange(e)} | |
/> | |
<input type="submit" /> | |
</form> | |
</div> | |
); | |
} | |
} | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
class Form extends Component { | |
render() { | |
return( | |
<div className="Form"> | |
<li> {this.props.formElement} </li> | |
</div> | |
); | |
} | |
} | |
export default Form; |
And that is all that there is to it. With just these steps it is possible to add new items to the form and output them to the page.