Week 8: React II
INFO 253A: Front-end Web Architecture
Kay Ashaolu
React Chapter 4:
Forms, Validation, and Simple Animation
Introduction to Forms in React
- Forms are essential for user interaction in web applications.
- Handling forms in React involves managing state and event handlers.
Managing Form Input and State
- Use the
useState
hook to manage form input state. - Example:
const [text, setText] = useState('');
- Connect form inputs to state using
value
andonChange
props. - Reflects user input in the component's state.
Example: Creating the FeedbackForm Component
- Create a new component:
FeedbackForm.jsx
. - Use the shared
Card
component to wrap the form for consistent styling. - Structure:
<Card>
<form>
{/* Form elements go here */}
</form>
</Card>
Using Custom Components
- Reuse components like
Card
andButton
to maintain consistency. - Create a
Button
component with customizable props. - Example Button Component Usage:
<Button type="submit" version="primary">
Send
</Button>
Creating a Custom Button Component
- Allows for reusable and customizable buttons across the app.
- Accepts props like
type
,version
,isDisabled
. - Button Component Implementation:
const Button = ({ children, version, type, isDisabled }) => {
return (
<button type={type} disabled={isDisabled} className={`btn btn-${version}`}>
{children}
</button>
);
};
Props and Default Props in Components
- Define default prop values using
defaultProps
. - Ensures components have default behavior if no props are passed.
- Example:
Button.defaultProps = {
version: 'primary',
type: 'button',
isDisabled: false,
};
Adding PropTypes for Type Checking
- Use
prop-types
library for runtime prop type checking. - Helps catch bugs by ensuring components receive correct prop types.
- Example:
import PropTypes from 'prop-types';
Button.propTypes = {
children: PropTypes.node.isRequired,
version: PropTypes.string,
type: PropTypes.string,
isDisabled: PropTypes.bool,
};
Implementing Real-Time Form Validation
- Disable submit button until input meets criteria (e.g., at least 10 characters).
- Use state to manage button disabled state and validation messages.
- Example:
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);
};
Handling Form Submission
- Add
onSubmit
handler to the form element. - Prevent default browser behavior with
e.preventDefault()
. - Collect form data and update state or communicate with parent components.
Conditional Rendering Based on Form State
- Show validation messages only when necessary.
- Use conditional rendering in JSX.
- Example:
{message && <div className="message">{message}</div>}
- The message appears only if
message
is not empty.
Example: Creating the RatingSelect Component
- Component for selecting a rating (1-10).
- Uses styled radio buttons for user selection.
- Manages selected rating with its own state.
const [selected, setSelected] = useState(10);
const handleChange = (e) => {
setSelected(+e.currentTarget.value);
};
Lifting State Up in React
- Share state between components by lifting it up to a common ancestor.
- Pass functions as props to child components to update parent state.
- Example in
FeedbackForm.jsx
:
<RatingSelect select={(rating) => setRating(rating)} />
- In
RatingSelect.jsx
, callselect(selected)
to update parent state.
Adding New Feedback Items to State
- Collect input data and create a new feedback object.
- Use
useState
to manage the list of feedback items. - Example:
const addFeedback = (newFeedback) => {
setFeedback([newFeedback, ...feedback]);
};
Using UUIDs for Unique IDs
- Install
uuid
library to generate unique IDs for new items. - Ensures each feedback item has a unique identifier.
- Example:
import { v4 as uuidv4 } from 'uuid';
const newFeedback = {
id: uuidv4(),
text,
rating,
};
Updating Global State in React
- Use state setters to update state immutably.
- Avoid direct mutation of state for predictability and performance.
- Example:
setFeedback([newFeedback, ...feedback]);
- Prepends the new feedback to the existing list.
Recap and Key Takeaways
- Forms in React require careful state management.
- Custom components promote code reusability and maintainability.
- Real-time validation improves user experience.
- Managing global state allows for dynamic and interactive applications.
React Chapter 5: Creating Routes and Links
The Role of Routing in Web Applications
- Routing allows navigation between different views without full page reloads
- Essential for Single Page Applications (SPAs)
- Maintains browser history and enables deep linking
- Enhances user experience with faster navigation
React and Client-Side Routing
- React focuses on building UI components
- Does not include built-in routing
- react-router-dom is the de facto standard for routing in React apps
- Provides components and hooks for declarative routing
Installing react-router-dom
npm install react-router-dom
- Install via npm to add routing capabilities
- Includes components like
BrowserRouter
,Routes
,Route
,Link
, etc.
Creating Links with the Link
Component
- Use
Link
instead of<a>
for internal navigation
import { Link } from 'react-router-dom';
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
);
}
- Prevents full page reloads
- Enables client-side routing and preserves application state
Using NavLink
for Active Links
-
NavLink
applies styling to the active link
import { 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>
);
}
- Customize active styles using
className
orstyle
props - Helps users identify the current page
Dynamic Routes with URL Parameters
- Define routes with dynamic parameters
<Route path="/post/:id" element={<Post />} />
- Access parameters using
useParams
hook
import { useParams } from 'react-router-dom';
function Post() {
const { id } = useParams();
return <h1>Post ID: {id}</h1>;
}
- Enables dynamic content based on the URL
- Commonly used for user profiles, articles, etc.
Programmatic Navigation with useNavigate
- Navigate in response to events or logic
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>;
}
- Facilitates redirects after actions like form submissions
Nested Routes and the Outlet
Component
- Define nested routes for complex layouts
import { Outlet } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Outlet />
</div>
);
}
Nested Routes and the Outlet
Component
- Use
Outlet
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>
- Organizes routes hierarchically
- Enhances code readability and maintainability
Summary and Best Practices
- Routing is integral to SPA architecture
- React Router enhances navigation without page reloads
- Always use
Link
orNavLink
for internal links - Utilize hooks like
useParams
anduseNavigate
for dynamic routing - Keep routes organized and consider nested routes for complex apps
React Chapter 6:
Context API, useContext Hook, and Deployment
Introduction to Context API
- Problem: Prop drilling makes state management cumbersome in large applications.
- Solution: Context API allows passing data through the component tree without manually passing props at every level.
- Benefit: Simplifies state management and makes code cleaner and more maintainable.
Prop Drilling Issue
- Passing props through multiple nested components becomes messy.
- Difficult to manage in large applications with deep component hierarchies.
- Example of prop drilling in
App.js
:
<FeedbackList feedback={feedback} handleDelete={deleteFeedback} />
Creating Context and Provider
-
Step 1: Import
createContext
anduseState
from React.
import { createContext, useState } from 'react';
- Step 2: Create a new context.
const FeedbackContext = createContext();
- Step 3: Create a provider component.
export const FeedbackProvider = ({ children }) => {
// State and functions here
return (
<FeedbackContext.Provider value={{ /* values */ }}>
{children}
</FeedbackContext.Provider>
);
};
Setting Up FeedbackContext.js
- Initialize state within the provider.
const [feedback, setFeedback] = useState([
{ id: 1, text: 'This item is from context', rating: 10 },
]);
- Provide state and functions via the
value
prop.
<FeedbackContext.Provider value={{ feedback }}>
{children}
</FeedbackContext.Provider>
Wrapping App with FeedbackProvider
- Import
FeedbackProvider
inApp.js
.
import { FeedbackProvider } from './context/FeedbackContext';
- Wrap the entire application.
return (
<FeedbackProvider>
{/* Your components */}
</FeedbackProvider>
);
Consuming Context with useContext
- Import
useContext
and the context.
import { useContext } from 'react';
import FeedbackContext from '../context/FeedbackContext';
- Use the context within a component.
const { feedback } = useContext(FeedbackContext);
Updating Components to Use Context
- Remove props drilling by accessing context directly.
- Example in
FeedbackList.js
:
const { feedback } = useContext(FeedbackContext);
- No longer need to pass
feedback
as a prop fromApp.js
.
Moving Functions to Context
- Move state manipulation functions to context.
const deleteFeedback = (id) => {
setFeedback(feedback.filter((item) => item.id !== id));
};
- Provide functions via the
value
prop.
<FeedbackContext.Provider value={{ feedback, deleteFeedback }}>
{children}
</FeedbackContext.Provider>
Updating the Form and List Components
- Access functions from context using
useContext
.
const { deleteFeedback } = useContext(FeedbackContext);
- Remove function props from components and use context functions instead.
- Simplifies component interfaces and reduces prop drilling.
Implementing Edit Feedback Feature
- Add an edit icon to
FeedbackItem
.
<button onClick={() => editFeedback(item)}>
<FaEdit color='purple' />
</button>
- Create
editFeedback
function in context to handle the edit state.
const [feedbackEdit, setFeedbackEdit] = useState({
item: {},
edit: false,
});
const editFeedback = (item) => {
setFeedbackEdit({
item,
edit: true,
});
};
Managing Side Effects with useEffect
- Import and use
useEffect
to handle side effects.
import { useEffect } from 'react';
useEffect(() => {
if (feedbackEdit.edit === true) {
// Update form state
}
}, [feedbackEdit]);
- Update form fields when the edit state changes.
Updating Feedback Item
- Add
updateFeedback
function in context.
const updateFeedback = (id, updItem) => {
setFeedback(
feedback.map((item) => (item.id === id ? { ...item, ...updItem } : item))
);
};
- Modify
FeedbackForm
to handle updates.
if (feedbackEdit.edit === true) {
updateFeedback(feedbackEdit.item.id, newFeedback);
} else {
addFeedback(newFeedback);
}
Deploying to Netlify
- Create a GitHub repository and push your code.
- Sign up for Netlify and create a new site from Git.
- Select your repository and configure build settings:
-
Build Command:
npm run build
-
Publish Directory:
build
-
Build Command:
- Deploy the site and access it via the provided URL.
Alternative Deployment Options
- Vercel: Easy deployment with Git integration.
- AWS Amplify: Scalable hosting solution.
- GitHub Pages: Suitable for static sites.
- Heroku: Can be used with a server-side component.
Conclusion and Next Steps
- Context API simplifies state management in React apps.
- useContext hook allows consuming context easily.
- Deployment is straightforward with platforms like Netlify.
Week 8 - React 2
By kayashaolu