Lab 15: Form Values to State
Objectives
- Add form data to component state
- Make form fields controlled components
- Handle submission of the form
Steps
Add form data to component state
Open the file
src\projects\ProjectForm.js.To the
propTypes, add aprojectprop.src\projects\ProjectForm.js...ProjectForm.propTypes = {+ project: PropTypes.instanceOf(Project),onSave: PropTypes.func.isRequired,onCancel: PropTypes.func.isRequired};...Destructure the
projectprop in the function component signature and rename itinitialProjectso that we can name our state variableproject. Next, create a state variableprojectusing theuseStatehook.src\projects\ProjectForm.js- import React from 'react';+ import React, { useState } from 'react';function ProjectForm({+ project: initialProject,onSave,onCancel,}) {+ const [project, setProject] = useState(initialProject);const handleSubmit = (event) => {event.preventDefault();onSave(new Project({ name: 'Updated Project' }));};...}
Make form fields controlled components
Make all
<input />s and<textarea />s controlled components by assigning their values to aprojectproperty onstate.Write a
handleChangeevent handler and wire it up toonChangeevent of all the form fields.The form field types that need to be handled include:
<input type="text" /><input type="number" /><input type="checkbox" /><textarea />Alternatively, you could write a separate handler for each of the form field types and invoke them as appropriate but this can be tedious and more difficult to maintain.
src\projects\ProjectForm.js
Handle submission of the form
In
handleSubmit, when calling theonSaveproppassstate.projectinstead ofnew Project({ name: 'Updated Project' }).src\projects\ProjectForm.js
In
ProjectListset theprojectprop into the<ProjectForm />.src\projects\ProjecList.js...function ProjectList({ projects, onSave }) {const [projectBeingEdited, setProjectBeingEdited] = useState({});const handleEdit = (project) => {setProjectBeingEdited(project);};const cancelEditing = () => {setProjectBeingEdited({});};return (<div className="row">{projects.map((project) => (<div key={project.id} className="cols-sm">{project === projectBeingEdited ? (<ProjectForm+ project={project}onSave={onSave}onCancel={cancelEditing}/>) : (<ProjectCard project={project} onEdit={handleEdit} />)}</div>))}</div>);}export default ProjectList;ProjectsPage update the project.
src\projects\ProjectsPage.jsimport React, { Fragment,+ useState } from 'react';import { MOCK_PROJECTS } from './MockProjects';import ProjectList from './ProjectList';function ProjectsPage() {+ const [projects, setProjects] = useState(MOCK_PROJECTS);const saveProject = (project) => {- console.log('Saving project: ', project);+ let updatedProjects = projects.map((p) => {+ return p.id === project.id ? project : p;+ });+ setProjects(updatedProjects);};return (<Fragment><h1>Projects</h1>- <ProjectList onSave={saveProject} projects={MOCK_PROJECTS} />+ <ProjectList onSave={saveProject} projects={projects} /></Fragment>);}export default ProjectsPage;Verify the application is working by following these steps in your browser.
- Click the edit button for a project.
- Change the project name in the form.
- Click save on the form.
- Verify the card shows the updated data.
Note that if you refresh your browser page your changes will not persist because the updates are only happening in the browser's memory. We will get a more permanent save working in a future lab when we communicate to our backend web API.