Today we will create a Wish List app. This app will use a form.
Create the client app
npx create-react-app wish-list
Change into the app folder
cd wish-list
Install dependencies
npm install
Run the app
npm start
See a spinning logo?
Back at terminal lets open Visual Studio Code
code .
Edit the CSS file getting rid of un used styles
/src/app.css
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 10vmin;
pointer-events: none;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
Edit the app file to remove things we don't need and make the App
a React component.
/src/app.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
</div>
);
}
}
export default App;
Now we will create a component and associated css file for the form.
Make a new file for the form styling
/src/component/WishForm.css
.wish-form {
margin-left: 20px;
}
form {
font-size: 16px;
max-width: 500px;
}
input {
margin: 5px 0 25px 0;
display: block;
width: 100%;
font-size: 16px;
}
label {
display: block;
width: 100%;
}
button {
width: 120px;
padding: 10px 30px;
}
Make a new file for the form. We will be adding functions to this component so we will extend Component rather then use a functional component.
/src/component/WishForm.js
import React, { Component } from 'react';
import './WishForm.css';
class WishForm extends Component {
render(){
return (
<div className="wish-form">
<h1>Wish Form</h1>
<form>
<label htmlFor="name">Name</label>
<input type="text" id="name" placeholder="name" />
<label htmlFor="priority">Priority</label>
<input type="number" id="priority" placeholder="1" />
<button>Save</button>
</form>
</div>
);
}
}
export default WishForm;
Update the App.js
to use the form component
We will add the component and the import for it.
We are using the uppercase Form to differentiate it from the HTML form element.
import React, { Component } from 'react';
import WishForm from './components/WishForm'
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
<WishForm />
</div>
);
}
}
export default App;
The app should now run. Displaying the logo from App.js
and the heading and form from WishForm.js
Clicking the button refreshes the page.
Add a handler for the click event tot he form button.
/src/component/WishForm.js
class WishForm extends Component {
handleClick = () => {
console.log('clicked')
}
render(){
return (
<div className="wish-form">
<h1>Wish Form</h1>
<form>
<label htmlFor="name">Name</label>
<input type="text" id="name" placeholder="name" />
<label htmlFor="priority">Priority</label>
<input type="number" id="priority" placeholder="1" />
<button onClick={this.handleClick}>Save</button>
</form>
</div>
);
}
}
The page still refreshes.
Update the handler to capture the event parameter (we had been ignoring it but not providing it with a name). The event is similar to what we had been using in vanilla javascript but we also have extra React features added to it. Try console logging e.currentTarget
.
/src/component/WishForm.js
handleClick = (e) => {
e.preventDefault();
console.log(e)
}
How will we capture what has been entered into the field of the form?
Add a constructor
to initialize the state and add a change handler to the name
input field.
/src/component/WishForm.js
class WishForm extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
priority: ''
};
}
handleClick = (e) => {
e.preventDefault();
console.log(e)
}
handleNameChange = (e) => {
console.log(e)
}
render(){
return (
<div className="wish-form">
<h1>Wish Form</h1>
<form>
<label htmlFor="name">Name</label>
<input onChange={this.handleNameChange} type="text" id="name" placeholder="name" />
<label htmlFor="priority">Priority</label>
<input type="number" id="priority" placeholder="1" />
<button onClick={this.handleClick}>Save</button>
</form>
</div>
);
}
}
We can also use console log to check the value of e.target
and e.target.value
.
What is e.currentTarget.value
?
We can use this value to record the state
.
/src/component/WishForm.js
handleNameChange = (e) => {
console.log(e)
console.log(e.target)
console.log(e.target.value)
console.log(e.target.id)
this.setState({ name: e.target.value})
}
Lets confirm this is being saved by logging sate
in the render
method:
console.log(this.state);
Working.
We will need to do the same thing for the priority
field but lets for a way to reuse this method. Let looks at:
console.log(e.target.id)
Now lets use this to setState
.
/src/component/WishForm.js
handleNameChange = (e) => {
this.setState({ [e.target.id]: e.target.value})
}
We can see the state
being logged to confirm that it is working.
Let change the handleNameChange
to have a more generic name and add it to an onClick
for both the input
fields.
/src/component/WishForm.js
handleChange = (e) => {
this.setState({ [e.target.id]: e.target.value})
}
render(){
console.log(this.state);
return (
<div className="wish-form">
<h1>Wish Form</h1>
<form>
<label htmlFor="name">Name</label>
<input onChange={this.handleChange} type="text" id="name" placeholder="name" />
<label htmlFor="priority">Priority</label>
<input onChange={this.handleChange} type="number" id="priority" placeholder="1" />
<button onClick={this.handleClick}>Save</button>
</form>
</div>
);
}
<br>
Create a method to receive the saved wish from the WishForm
.
/src/App.js
class App extends Component {
addNewWishHandler = () => {
console.log('Adding a new wish');
}
render() {
return (
<div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
<WishForm addNewWish={this.addNewWishHandler} />
</div>
);
}
}
Now use this method in our WishForm
to pass back the values from the newly crated wish.
/src/component/WishForm.js
handleClick = (e) => {
e.preventDefault();
console.log(e)
const newWish = {name: this.state.name, priority: this.state.priority }
this.props.addNewWish(newWish)
}
Confirm that the wish is being past back to the App
component.
/src/App.js
addNewWishHandler = (newWish) => {
console.log('Adding a new wish');
console.log(newWish);
}
Create an element in App
component's state for the wishes and store the value in the addNewWishHandler
. Also display the list of wishes.
/src/App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
wishes: []
};
}
addNewWishHandler = (newWish) => {
this.setState({ wishes: [...this.state.wishes, newWish]})
}
render() {
return (
<div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
<WishForm addNewWish={this.addNewWishHandler} />
{this.state.wishes.map((item, index) => (
<p>{index}: {item.name} ({item.priority})</p>
))}
</div>
);
}
}
/src/App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
wishes: [],
adding: false
};
}
addNewWishHandler = (newWish) => {
console.log('Adding a new wish');
console.log(newWish);
this.setState({
wishes: [...this.state.wishes, newWish],
adding: false
})
}
showAddWishForm = () => {
this.setState({
adding: true
})
}
render() {
console.log(this.state)
return (
<div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
{this.state.adding ? <WishForm addNewWish={this.addNewWishHandler} />
: <button onClick={this.showAddWishForm}>Add a wish</button>}
{this.state.wishes.map((item, index) => (
<p>{index}: {item.name} ({item.priority})</p>
))}
</div>
);
}
}
-
Add a
textarea
input field to the form fordescription
. See example here https://reactjs.org/docs/forms.html -
Add a
checkbox
for completed to the form. See example here https://reactjs.org/docs/forms.html -
Update the
App
component to display the two new fields. -
Add styling to the wish list in the
App
component -
Add styling so the list does not move down the screen when the Wish Form is displayed.
Add the ability to edit a wish.
Hint: Add an id the the wishes. When a new wish is created it will be given an id.