INFO 253A: Front-end Web Architecture
Kay Ashaolu
useState
hook to manage form input state. const [text, setText] = useState('');
value
and onChange
props.FeedbackForm.jsx
.Card
component to wrap the form for consistent styling. <Card>
<form>
{/* Form elements go here */}
</form>
</Card>
Card
and Button
to maintain consistency.Button
component with customizable props. <Button type="submit" version="primary">
Send
</Button>
type
, version
, isDisabled
. const Button = ({ children, version, type, isDisabled }) => {
return (
<button type={type} disabled={isDisabled} className={`btn btn-${version}`}>
{children}
</button>
);
};
defaultProps
. Button.defaultProps = {
version: 'primary',
type: 'button',
isDisabled: false,
};
prop-types
library for runtime prop type checking. import PropTypes from 'prop-types';
Button.propTypes = {
children: PropTypes.node.isRequired,
version: PropTypes.string,
type: PropTypes.string,
isDisabled: PropTypes.bool,
};
const [btnDisabled, setBtnDisabled] = useState(true);
const [message, setMessage] = useState('');
const handleTextChange = (e) => {
if (text.trim().length <= 10) {
setBtnDisabled(true);
setMessage('Text must be at least 10 characters');
} else {
setBtnDisabled(false);
setMessage('');
}
setText(e.target.value);
};
onSubmit
handler to the form element.e.preventDefault()
. {message && <div className="message">{message}</div>}
message
is not empty. const [selected, setSelected] = useState(10);
const handleChange = (e) => {
setSelected(+e.currentTarget.value);
};
FeedbackForm.jsx
: <RatingSelect select={(rating) => setRating(rating)} />
RatingSelect.jsx
, call select(selected)
to update parent state.useState
to manage the list of feedback items. const addFeedback = (newFeedback) => {
setFeedback([newFeedback, ...feedback]);
};
uuid
library to generate unique IDs for new items. import { v4 as uuidv4 } from 'uuid';
const newFeedback = {
id: uuidv4(),
text,
rating,
};
setFeedback([newFeedback, ...feedback]);
react-router-dom
npm install react-router-dom
BrowserRouter
, Routes
, Route
, Link
, etc.Link
ComponentLink
instead of <a>
for internal navigationimport { Link } from 'react-router-dom';
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
);
}
NavLink
for Active LinksNavLink
applies styling to the active linkimport { NavLink } from 'react-router-dom';
function Navbar() {
return (
<nav>
<NavLink to="/" className={({ isActive }) => (isActive ? 'active' : '')}>
Home
</NavLink>
<NavLink to="/about" className={({ isActive }) => (isActive ? 'active' : '')}>
About
</NavLink>
</nav>
);
}
className
or style
props<Route path="/post/:id" element={<Post />} />
useParams
hookimport { useParams } from 'react-router-dom';
function Post() {
const { id } = useParams();
return <h1>Post ID: {id}</h1>;
}
useNavigate
import { useNavigate } from 'react-router-dom';
function ContactForm() {
const navigate = useNavigate();
const handleSubmit = () => {
// Submit form logic
navigate('/thank-you');
};
return <button onClick={handleSubmit}>Submit</button>;
}
Outlet
Componentimport { Outlet } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Outlet />
</div>
);
}
Outlet
ComponentOutlet
to render child routes within parent components<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="stats" element={<Stats />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
Link
or NavLink
for internal linksuseParams
and useNavigate
for dynamic routingApp.js
: <FeedbackList feedback={feedback} handleDelete={deleteFeedback} />
createContext
and useState
from React. import { createContext, useState } from 'react';
const FeedbackContext = createContext();
export const FeedbackProvider = ({ children }) => {
// State and functions here
return (
<FeedbackContext.Provider value={{ /* values */ }}>
{children}
</FeedbackContext.Provider>
);
};
FeedbackContext.js
const [feedback, setFeedback] = useState([
{ id: 1, text: 'This item is from context', rating: 10 },
]);
value
prop. <FeedbackContext.Provider value={{ feedback }}>
{children}
</FeedbackContext.Provider>
FeedbackProvider
FeedbackProvider
in App.js
. import { FeedbackProvider } from './context/FeedbackContext';
return (
<FeedbackProvider>
{/* Your components */}
</FeedbackProvider>
);
useContext
useContext
and the context. import { useContext } from 'react';
import FeedbackContext from '../context/FeedbackContext';
const { feedback } = useContext(FeedbackContext);
FeedbackList.js
: const { feedback } = useContext(FeedbackContext);
feedback
as a prop from App.js
. const deleteFeedback = (id) => {
setFeedback(feedback.filter((item) => item.id !== id));
};
value
prop. <FeedbackContext.Provider value={{ feedback, deleteFeedback }}>
{children}
</FeedbackContext.Provider>
useContext
. const { deleteFeedback } = useContext(FeedbackContext);
FeedbackItem
. <button onClick={() => editFeedback(item)}>
<FaEdit color='purple' />
</button>
editFeedback
function in context to handle the edit state. const [feedbackEdit, setFeedbackEdit] = useState({
item: {},
edit: false,
});
const editFeedback = (item) => {
setFeedbackEdit({
item,
edit: true,
});
};
useEffect
useEffect
to handle side effects. import { useEffect } from 'react';
useEffect(() => {
if (feedbackEdit.edit === true) {
// Update form state
}
}, [feedbackEdit]);
updateFeedback
function in context. const updateFeedback = (id, updItem) => {
setFeedback(
feedback.map((item) => (item.id === id ? { ...item, ...updItem } : item))
);
};
FeedbackForm
to handle updates. if (feedbackEdit.edit === true) {
updateFeedback(feedbackEdit.item.id, newFeedback);
} else {
addFeedback(newFeedback);
}
npm run build
build