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.tsx.
- On the - ProjectFormPropsinterface add the- projectprop to it.- src\projects\ProjectForm.tsxinterface ProjectFormProps {+ project: Project;onSave: (project: Project) => void;onCancel: () => void;}
- Destructure the - projectprop in the function component signature and rename it- initialProjectso that we can name our state variable- project. Next, create a state variable- projectusing the- useStatehook.- src\projects\ProjectForm.tsx- import React, { SyntheticEvent } from 'react';+ import React, { SyntheticEvent, useState } from 'react';function ProjectForm({+ project: initialProject,onSave,onCancel,}: ProjectFormProps) {+ const [project, setProject] = useState(initialProject);const handleSubmit = (event: SyntheticEvent) => {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 a- projectproperty on- state.- Write a - handleChangeevent handler and wire it up to- onChangeevent 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.tsx
 
Handle submission of the form
- In - handleSubmit, when calling the- onSave- proppass- state.projectinstead of- new Project({ name: 'Updated Project' }).- src\projects\ProjectForm.tsx
- In - ProjectListset the- projectprop into the- <ProjectForm />.- src\projects\ProjecList.tsx...function ProjectList({ projects, onSave }: ProjectListProps) {const [projectBeingEdited, setProjectBeingEdited] = useState({});const handleEdit = (project: 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.tsximport React, { Fragment,+ useState } from 'react';import { MOCK_PROJECTS } from './MockProjects';import ProjectList from './ProjectList';+ import { Project } from './Project';function ProjectsPage() {+ const [projects, setProjects] = useState<Project[]>(MOCK_PROJECTS);const saveProject = (project: Project) => {- console.log('Saving project: ', project);+ let updatedProjects = projects.map((p: Project) => {+ 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.