Lab 14: Component Communication through Multiple Levels
Objectives
- In a child component, accept a function as a prop and invoke it and pass a parameter
- At the next level in the component hierarchy, accept a function as a prop and invoke it
- In a parent component, implement a function and pass it as a prop to a child component
Steps
In a child component, accept a function as a prop and invoke it and pass a parameter
Open the file
src\projects\ProjectForm.tsx
.On the
ProjectFormProps
interface, add anonSave
function that requires aproject
as a parameter and returnsvoid
.src\projects\ProjectForm.tsx
...
+ import { Project } from './Project';
interface ProjectFormProps {
+ onSave: (project: Project) => void;
onCancel: () => void;
}
...Create an event handler function
handleSubmit
to handle the submission of the form.The function should prevent the default behavior of the browser to post to the server and then invoke the function passed into the
onSave
prop
and pass a newProject
that you create inline for now with just a name as shown below.Update the
<form>
tag in therender
method to invoke handleSubmit and pass the SyntheticEvent object representing the DOM submit event.src\projects\ProjectForm.tsx
+ import React, { SyntheticEvent } from 'react';
...
- function ProjectForm({ onCancel }: ProjectFormProps) {
+ function ProjectForm({ onSave, onCancel }: ProjectFormProps) {
+ const handleSubmit = (event: SyntheticEvent) => {
+ event.preventDefault();
+ onSave(new Project({ name: 'Updated Project' }));
+ };
return (
<form className="input-group vertical"
+ onSubmit={handleSubmit}
>
<label htmlFor="name">Project Name</label>
<input type="text" name="name" placeholder="enter name" />
<label htmlFor="description">Project Description</label>
<textarea name="description" placeholder="enter description" />
<label htmlFor="budget">Project Budget</label>
<input type="number" name="budget" placeholder="enter budget" />
<label htmlFor="isActive">Active?</label>
<input type="checkbox" name="isActive" />
<div className="input-group">
<button className="primary bordered medium">Save</button>
<span />
<button type="button" className="bordered medium" onClick={onCancel}>
cancel
</button>
</div>
</form>
);
}
export default ProjectForm;
At the next level in the component hierarchy, accept a function as a prop and invoke it
Open the file
src\projects\ProjectList.tsx
.On the
ProjectListProps
interface, add anonSave
event handler that requies aproject
as a parameter and returnsvoid
.src\projects\ProjectList.tsx
interface ProjectListProps {
projects: Project[];
+ onSave: (project: Project) => void;
}Update the
<ProjectForm>
component tag to handle aonSave
event and have it invoke the function passed into theonSave
prop
.src\projects\ProjectList.tsx
interface ProjectListProps {
projects: Project[];
onSave: (project: Project) => void;
}
- function ProjectList({ projects }: ProjectListProps) {
+ 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
+ onSave={onSave}
onCancel={cancelEditing} />
) : (
<ProjectCard project={project} onEdit={handleEdit} />
)}
</div>
))}
</div>
);
}
export default ProjectList;
In a parent component, implement a function and pass it as a prop to a child component
In the file
src\projects\ProjectsPage.tsx
:- Add a
saveProject
event handler that takes aproject
toProjectPage
andconsole.log
's the project out. - Wire up the onSave event of the
<ProjectList />
component rendered in theProjectPage
to thesaveProject
event handler.
src\projects\ProjectsPage.tsx
import React, { Fragment } from 'react';
import { MOCK_PROJECTS } from './MockProjects';
import ProjectList from './ProjectList';
+ import { Project } from './Project';
function ProjectsPage() {
+ const saveProject = (project: Project) => {
+ console.log('Saving project: ', project);
+ };
return (
<Fragment>
<h1>Projects</h1>
<ProjectList
+ onSave={saveProject}
projects={MOCK_PROJECTS} />
</Fragment>
);
}
export default ProjectsPage;- Add a
Verify the application is working by following these steps:
- Open the application in your browser and refresh the page.
- Open the Chrome DevTools to the
console
(F12
orfn+F12
on laptop). - Click the edit button for a project.
- Click the save button on the form.
- Verify the updated project is logged to the Chrome DevTools
console
.Note that the
ProjectCard
info will not be updated at this point.