1. Setting Up the Project
Create a New React Project: Run the following command to create a new React project:
Copy npx create-react-app react-formProfile-app
cd react-formProfile-app
Install Bootstrap CSS: Install Bootstrap using npm:
Copy npm install bootstrap
Import Bootstrap in the main.jsx
file:
Copy import 'bootstrap/dist/css/bootstrap.min.css';
Setup Folder Structure: Create a components
folder inside the src
directory:
Copy src/
|-- components/
|-- FormProfile.jsx
|-- AppFormProfile.jsx
The parent component manages the state for the form data and profiles, and passes the necessary props to the child component.
Code for AppFormProfile.jsx
:
Copy import React, { useState } from 'react';
import FormProfile from './components/FormProfile';
import 'bootstrap/dist/css/bootstrap.min.css';
function AppFormProfile() {
const [formData, setFormData] = useState({
userImage: './src/assets/IMG_0003.JPG', // Replace with a real image URL,
name: '',
email: '',
profession: ''
});
const [profiles, setProfiles] = useState([]);
const handleChange = (event) => {
const { name, value } = event.target;
setFormData({
...formData, // create a copy of the formData array.
[name]: value
}); //update form data input
};
const handleSubmit = (event) => {
event.preventDefault();
setProfiles([...profiles, formData]);
setFormData({ userImage: '', name: '', email: '', profession: '' });
}; //clear form inputs
return (
<div className="container mt-5">
<h1 className="text-center">React Profile App</h1>
<form onSubmit={handleSubmit} className="mb-4">
<div className="mb-3">
<input
type="text"
name="userImage"
value={formData.userImage}
onChange={handleChange}
placeholder="Image URL"
className="form-control"
/>
</div>
<div className="mb-3">
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
className="form-control"
/>
</div>
<div className="mb-3">
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
className="form-control"
/>
</div>
<div className="mb-3">
<input
type="text"
name="profession"
value={formData.profession}
onChange={handleChange}
placeholder="Profession"
className="form-control"
/>
</div>
<button type="submit" className="btn btn-primary">Add Profile</button>
</form>
<div className="profile-container d-flex flex-wrap gap-4">
{profiles.map((profile, index) => (
<FormProfile
key={index}
userImage={profile.userImage}
name={profile.name}
email={profile.email}
profession={profile.profession}
/>
))}
</div>
</div>
);
}
export default AppFormProfile;
The child component receives props from the parent and renders the user profile.
Code for FormProfile.jsx
:
Copy import React from 'react';
import PropTypes from 'prop-types';
function FormProfile({ userImage, name, email, profession }) {
return (
<div className="user-profile d-flex border p-3 rounded">
<div className="left-item me-3">
<img src={userImage} alt={name} className="img-fluid rounded" style={{ width: '100px', height: '100px' }} />
</div>
<div className="right-item d-flex flex-column">
<h5>{name}</h5>
<p>{email}</p>
<p>{profession}</p>
</div>
</div>
);
}
FormProfile.propTypes = {
userImage: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
profession: PropTypes.string.isRequired,
};
export default FormProfile;
4. Styling with Bootstrap
Leverage Bootstrap classes for styling. Use d-flex
, flex-row
, and flex-column
for layouts. Add custom styles in App.css
if necessary.
5. Run the Application
Start the application using the following command:
Final Output
The app will display a form at the top for adding profiles. Below the form, profiles will be displayed in a flexbox layout with images on the left and details on the right.
Summary
This walkthrough demonstrates how to:
Lift state up in the parent component.
Pass props to child components.
Use Bootstrap for responsive styling.
Manage forms and lists dynamically in React.
Challenge : Update the component to fetch image URLs from Unsplash and allow the user to select one.
Code for Updated AppFormProfileUpdated.jsx
:
Copy import React, { useState, useEffect } from 'react';
import FormProfileUpdated from './components/FormProfileUpdated.jsx';
const apiKey =''
function AppFormProfileUpdated() {
const [formData, setFormData] = useState({
userImage:'https://images.pexels.com/photos/2014422/pexels-photo-2014422.jpeg',
name: '',
email: '',
profession: ''
});
const [profiles, setProfiles] = useState([]);
const [imageOptions, setImageOptions] = useState([]);
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState(null)
useEffect(() => {
// Fetch image options from Unsplash
const fetchImages = async (query) => {
setIsLoading(true)
try {
const response = await fetch(
`https://api.pexels.com/v1/search?query=${query}&per_page=2`,
{
headers: {
Authorization: apiKey,
},
},
)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.json()
setImageOptions(data.photos)
console.log("Photos: ", data.photos)
} catch (error) {
setError('Failed to fetch images.')
} finally {
setIsLoading(false)
}
}
fetchImages('people')
}, []);
const handleChange = (event) => {
const { name, value } = event.target;
setFormData({
...formData,
[name]: value
});
};
const handleSubmit = (event) => {
event.preventDefault();
setProfiles([...profiles, formData]);
setFormData({ userImage: '', name: '', email: '', profession: '' });
};
return (
<div className="container mt-5">
<h1 className="text-center">React Profile App</h1>
<form onSubmit={handleSubmit} className="mb-4">
<div className="mb-3">
<label htmlFor="userImage" className="form-label">Select an Image:</label>
<select
id="userImage"
name="userImage"
value={formData.userImage}
onChange={handleChange}
className="form-select"
>
<option value="">Choose an image</option>
{imageOptions.map((url, index) => (
<option key={index} value={url}>{url}</option>
))}
</select>
</div>
<div className="mb-3">
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
className="form-control"
/>
</div>
<div className="mb-3">
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
className="form-control"
/>
</div>
<div className="mb-3">
<input
type="text"
name="profession"
value={formData.profession}
onChange={handleChange}
placeholder="Profession"
className="form-control"
/>
</div>
<button type="submit" className="btn btn-primary">Add Profile</button>
</form>
<div className="profile-container d-flex flex-wrap gap-4">
{profiles.map((profile, index) => (
<FormProfileUpdated
key={index}
userImage={profile.userImage}
name={profile.name}
email={profile.email}
profession={profile.profession}
/>
))}
</div>
</div>
);
}
export default AppFormProfileUpdated;
The child component receives props from the parent and renders the user profile.
Code for FormProfileUpdated.jsx
Copy import React from 'react';
import PropTypes from 'prop-types';
function FormProfileUpdated({ userImage, name, email, profession }) {
return (
<div className="user-profile d-flex border p-3 rounded">
<div className="left-item me-3">
<img src={userImage} alt={name} className="img-fluid rounded" style={{ width: '100px', height: '100px' }} />
</div>
<div className="right-item d-flex flex-column">
<h5>{name}</h5>
<p>{email}</p>
<p>{profession}</p>
</div>
</div>
);
}
FormProfile.propTypes = {
userImage: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
profession: PropTypes.string.isRequired,
};
export default FormProfileUpdated;
4. Styling with Bootstrap
Leverage Bootstrap classes for styling. Use d-flex
, flex-row
, and flex-column
for layouts. Add custom styles in App.css
if necessary.
5. Run the Application
Start the application using the following command:
Final Output
The app will display a form at the top for adding profiles. Below the form, profiles will be displayed in a flexbox layout with images on the left and details on the right.
Challenge : Capture Live Image from PC Camera
I want to modify App.jsx react component to capture the image data from the usb pc camera instead of using image URL.
App.jsx AppVideoProfile.jsx
Copy // App.jsx
import { useState } from 'react'
import './App.css'
import 'bootstrap/dist/css/bootstrap.css'
import FormProfile from './components/FormProfile.jsx'
function App() {
const [formData, setFormData] = useState({
userImage: './src/assets/IMG_0003.JPG', // Replace with a real image URL,
name: '',
email: '',
profession: '',
})
const [profiles, setProfiles] = useState([])
const handleChange = (event) => {
const { name, value } = event.target
setFormData({
...formData,
[name]: value,
}) //update form data input
}
const handleSubmit = (event) => {
event.preventDefault()
setProfiles([...profiles, formData])
setFormData({ userImage: '', name: '', email: '', profession: '' })//clear form inputs
}
return (
<>
<h1>Form Profile App</h1>
<div className="container mt-5 col col-md-8">
<form onSubmit={handleSubmit} className="mb-4">
<div className="mb-3">
<input
type="text"
name="userImage"
value={formData.userImage}
onChange={handleChange}
placeholder="Enter image url .e.g., https://unsplash.com/t/people"
className="form-control"
required="true"
/>
</div>
<div className="mb-3">
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
className="form-control"
required="true"
/>
</div>
<div className="mb-3">
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
className="form-control"
required="true"
/>
</div>
<div className="mb-3">
<input
type="text"
name="profession"
value={formData.profession}
onChange={handleChange}
placeholder="Profession"
className="form-control"
required="true"
/>
</div>
<button type="submit" className="btn btn-primary">
Add Profile
</button>
</form>
<div className="profile-container d-flex flex-wrap gap-4 ">
{profiles.map((profile, index) => (
<FormProfile
key={index}
userImage={profile.userImage}
name={profile.name}
email={profile.email}
profession={profile.profession}
/>
))}
</div>
</div>
</>
)
}
export default App
Copy // AppVideoProfile.jsx
import { useState, useRef, useEffect } from 'react';
import './App.css';
import 'bootstrap/dist/css/bootstrap.css';
import FormProfile from './components/FormProfile.jsx';
function App() {
const [formData, setFormData] = useState({
userImage: '',
name: '',
email: '',
profession: '',
});
const [profiles, setProfiles] = useState([]);
const videoRef = useRef(null);
const [cameraStream, setCameraStream] = useState(null);
useEffect(() => {
// Access the user's camera
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
setCameraStream(stream);
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
})
.catch((error) => {
console.error('Error accessing camera:', error);
});
return () => {
// Clean up the stream when the component unmounts
if (cameraStream) {
cameraStream.getTracks().forEach(track => track.stop());
}
};
}, []);
const captureImage = () => {
if (cameraStream && videoRef.current) {
const canvas = document.createElement('canvas');
canvas.width = videoRef.current.videoWidth;
canvas.height = videoRef.current.videoHeight;
const context = canvas.getContext('2d');
context.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height);
const imageDataURL = canvas.toDataURL('image/png');
setFormData({
...formData,
userImage: imageDataURL,
});
}
};
const handleChange = (event) => {
const { name, value } = event.target;
setFormData({
...formData,
[name]: value,
});
};
const handleSubmit = (event) => {
event.preventDefault();
setProfiles([...profiles, formData]);
setFormData({ userImage: '', name: '', email: '', profession: '' });
};
return (
<>
<h1>Form Profile App</h1>
<div className="container mt-5 col col-md-8">
<form onSubmit={handleSubmit} className="mb-4">
<div className="mb-3">
<video ref={videoRef} autoPlay playsInline />
<button onClick={captureImage} type="button" className="btn btn-secondary mt-2">Capture Image</button>
{formData.userImage && <img src={formData.userImage} alt="Captured" style={{ maxWidth: '200px' }} />}
</div>
{/* ... other input fields (name, email, profession) */}
<div className="mb-3">
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
className="form-control"
required="true"
/>
</div>
<div className="mb-3">
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
className="form-control"
required="true"
/>
</div>
<div className="mb-3">
<input
type="text"
name="profession"
value={formData.profession}
onChange={handleChange}
placeholder="Profession"
className="form-control"
required="true"
/>
</div>
<button type="submit" className="btn btn-primary">Add Profile</button>
</form>
<div className="profile-container d-flex flex-wrap gap-4 ">
{profiles.map((profile, index) => (
<FormProfile
key={index}
userImage={profile.userImage}
name={profile.name}
email={profile.email}
profession={profile.profession}
/>
))}
</div>
</div>
</>
);
}
export default App;
Result
Summary
This walkthrough demonstrates how to:
Lift state up in the parent component.
Pass props to child components.
Use Bootstrap for responsive styling.
Dynamically fetch and display image options from an external API.
Manage forms and lists dynamically in React.