INFO 253A: Front-end Web Architecture
Kay Ashaolu
const element = <h1>Hello, world!</h1>;
Tools and technologies:
node -v
in your terminal npx create-react-app feedback-app --use-npm
cd feedback-app
npm start
react
, react-dom
, and react-scripts
index.html
<div id="root"></div>
acts as a placeholder for our React appindex.js
<title>
to your app's name: <title>Feedback UI</title>
<div id="root"></div>
is crucial src/
└── (empty)
index.js
is missing import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
function App() {
return (
<h1>Hello from the App component</h1>
);
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
<App />
with <React.StrictMode>
for additional checks and warnings function App() {
return (
<h1>Hello from the App component</h1>
);
}
export default App;
React.createElement()
calls under the hood<div>
or <>
(fragment)className
instead of class
htmlFor
instead of for
{ }
function App() {
const title = 'Feedback UI';
return (
<div className="container">
<h1>{title}</h1>
<p>Collect feedback from users.</p>
</div>
);
}
{ }
to embed variables and expressions const user = 'Alice';
return (
<h1>Hello, {user}!</h1>
);
<p>The sum is: {2 + 3}</p> // Outputs: The sum is: 5
<h1>{title.toUpperCase()}</h1>
const isLoggedIn = true;
return (
<div>
{isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>}
</div>
);
&&
) Operator: const hasNotifications = true;
return (
<div>
{hasNotifications && <p>You have new messages.</p>}
</div>
);
map()
const feedbackItems = [
{ id: 1, text: 'Great product!' },
{ id: 2, text: 'Could be improved.' },
{ id: 3, text: 'Excellent support.' },
];
return (
<ul>
{feedbackItems.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
id
) <div className="container">
{/* ... */}
</div>
<label htmlFor="email">Email:</label>
<button onClick={handleClick}>Click Me</button>
<img src="image.png" alt="Example" />
<input type="text" />
<div></div>
without content<div />
if it's empty function Header() {
return <h1>Feedback UI</h1>;
}
return (
<header>
<div className="container">
<h2>Feedback UI</h2>
</div>
</header>
);
export
to make components available to other files.import
to bring components into a file. import Header from './components/Header';
<Header text="Hello World" />
function Header({ text }) {
return <h2>{text}</h2>;
}
Header.defaultProps = {
text: 'Feedback UI',
};
Header.propTypes = {
text: PropTypes.string,
};
style
attribute with a JavaScript object. const headerStyles = {
backgroundColor: 'blue',
color: 'red',
};
return <header style={headerStyles}>...</header>;
function Card({ children, reverse }) {
return (
<div className={`card ${reverse && 'reverse'}`}>
{children}
</div>
);
}
useState
is a Hook that lets you add state to functional components. const [rating, setRating] = useState(7);
// Updating state
setRating(10);
onClick
to respond to user interactions. <button onClick={() => setRating((prev) => prev + 1)}>
Increase Rating
</button>
const [feedback, setFeedback] = useState(FeedbackData);
map
to render lists of data as components. feedback.map((item) => (
<FeedbackItem key={item.id} item={item} />
));
<FeedbackItem handleDelete={deleteFeedback} />
{feedback.length === 0 ? (
<p>No Feedback Yet</p>
) : (
feedback.map((item) => <FeedbackItem ... />)
)}
function Card({ children }) {
return <div className="card">{children}</div>;
}
const deleteFeedback = (id) => {
setFeedback(feedback.filter((item) => item.id !== id));
};
function FeedbackStats({ feedback }) {
// Calculate average
return (
<div className="feedback-stats">
<h4>{feedback.length} Reviews</h4>
<h4>Average Rating: {average}</h4>
</div>
);
}
reduce
to compute aggregate data. let average =
feedback.reduce((acc, cur) => acc + cur.rating, 0) /
feedback.length;
toFixed
and replace
to format numbers. average = average.toFixed(1).replace(/[.,]0$/, '');
if (!feedback || feedback.length === 0) {
return <p>No Feedback Yet</p>;
}
import './index.css';
Imagine we have a simple React application with the following component hierarchy:
We want to share a piece of state (e.g., a counter) between ParentComponent
and ChildComponent
. To achieve this, we'll lift the state up to the App
component and pass it down via props, which can lead to prop drilling.
Lifting state up involves moving state to a common ancestor so that it can be shared among multiple components.
App.js
import React, { useState } from 'react';
import ParentComponent from './ParentComponent';
function App() {
const [counter, setCounter] = useState(0);
return (
<ParentComponent counter={counter} setCounter={setCounter} />
);
}
export default App;
ParentComponent.js
import React from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent({ counter, setCounter }) {
return (
<div>
<h1>Parent Component</h1>
<p>Counter in Parent: {counter}</p>
<button onClick={() => setCounter(counter + 1)}>
Increment in Parent
</button>
<ChildComponent counter={counter} setCounter={setCounter} />
</div>
);
}
export default ParentComponent;
ChildComponent.js
import React from 'react';
function ChildComponent({ counter, setCounter }) {
return (
<div>
<h2>Child Component</h2>
<p>Counter in Child: {counter}</p>
<button onClick={() => setCounter(counter - 1)}>
Decrement in Child
</button>
</div>
);
}
export default ChildComponent;
App
: The counter
state and setCounter
function are declared in the App
component.counter
and setCounter
are passed from App
to ParentComponent
, and then from ParentComponent
to ChildComponent
.ParentComponent
and ChildComponent
can both read and update the counter
.Prop drilling occurs when you pass props through intermediate components that do not need them, just to reach a component further down the tree.
ParentComponent
receives counter
and setCounter
primarily to pass them to ChildComponent
.ParentComponent
doesn't need these props for its own functionality, it's merely a conduit, which is prop drilling.