初始代码(点击展开)
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
const pizzaData = [
{
name: "Focaccia",
ingredients: "Bread with italian olive oil and rosemary",
price: 6,
photoName: "pizzas/focaccia.jpg",
soldOut: false,
},
{
name: "Pizza Margherita",
ingredients: "Tomato and mozarella",
price: 10,
photoName: "pizzas/margherita.jpg",
soldOut: false,
},
{
name: "Pizza Spinaci",
ingredients: "Tomato, mozarella, spinach, and ricotta cheese",
price: 12,
photoName: "pizzas/spinaci.jpg",
soldOut: false,
},
{
name: "Pizza Funghi",
ingredients: "Tomato, mozarella, mushrooms, and onion",
price: 12,
photoName: "pizzas/funghi.jpg",
soldOut: false,
},
{
name: "Pizza Salamino",
ingredients: "Tomato, mozarella, and pepperoni",
price: 15,
photoName: "pizzas/salamino.jpg",
soldOut: true,
},
{
name: "Pizza Prosciutto",
ingredients: "Tomato, mozarella, ham, aragula, and burrata cheese",
price: 18,
photoName: "pizzas/prosciutto.jpg",
soldOut: false,
},
];
function App() {
return (
<div className="container">
<Header />
<Menu />
<Footer />
</div>
);
}
function Header() {
const style = {};
return (
<header className="header">
<h1 style={style}>Fast React Pizza Co.</h1>
</header>
);
}
function Menu() {
const pizzas = pizzaData;
// const pizzas = [];
const numPizzas = pizzas.length;
return (
<main className="menu">
<h2>Our Menu</h2>
{numPizzas > 0 ? (
<ul className="pizzas">
{pizzas.map((pizza) => (
<Pizza pizzaObj={pizza} key={pizza.name} />
))}
</ul>
) : (
<p>We're still working on our menu. Please come back later</p>
)}
{/* <Pizza
name="Pizza Spinaci"
ingredient="Tomato, mozarella, spinach, and ricotta cheese"
photoName="pizzas/spinaci.jpg"
price={10}
/>
<Pizza
name="Pizza Funghi"
ingredient="Tomato, mushrooms"
price={12}
photoName="pizzas/funghi.jpg"
/> */}
</main>
);
}
function Pizza(props) {
console.log(props);
if (props.pizzaObj.soldOut) {
return null;
}
return (
<li className="pizza">
<img src={props.pizzaObj.photoName} alt={props.pizzaObj.name}></img>
<div>
<h3>{props.pizzaObj.name}</h3>
<p>{props.pizzaObj.ingredients}</p>
<span>{props.pizzaObj.price}</span>
</div>
</li>
);
}
function Footer() {
const hour = new Date().getHours();
const openHour = 20;
const closeHour = 22;
const isOpen = hour >= openHour && hour <= closeHour;
console.log(isOpen);
return (
<footer className="footer">
{isOpen ? (
<div className="order">
<p>We're open until {closeHour}:00. Come visit us or order online.</p>
<button className="btn">Order</button>
</div>
) : (
<p>
We're happy to welcome you between {openHour}:00 and {closeHour}
</p>
)}
</footer>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
在 React 开发中,将大型组件分解成更小、更易管理的部分是一种强大的实践。这不仅使代码更易读,还提高了可重用性和可维护性。在本教程中,我们将通过一个实际示例,探讨如何从现有组件中提取新组件,并使用 props 在它们之间传递数据。
为什么需要提取组件?
随着应用程序的增长,组件可能会变得越来越大、越来越复杂。当一个组件的 JSX 代码变得过长时,可能是时候考虑将其部分功能提取到新的组件中了。这种实践带来以下好处:
- 提高代码可读性 – 较小的组件更容易理解
- 增强可维护性 – 修改一个小组件比修改一个包含大量代码的组件要安全得多
- 促进重用 – 提取的组件可以在应用程序的其他部分使用
实例:提取 Order 组件
让我们紧接着之前的代码例子来理解这个概念。我们从一个 Footer 组件开始,其中包含一些条件渲染逻辑:
function Footer() {
const hour = new Date().getHours();
const openHour = 20;
const closeHour = 22;
const isOpen = hour >= openHour && hour <= closeHour;
return (
<footer className="footer">
{isOpen ? (
<div className="order">
<p>We're open until {closeHour}:00. Come visit us or order online.</p>
<button className="btn">Order</button>
</div>
) : (
<p>
We're happy to welcome you between {openHour}:00 and {closeHour}
</p>
)}
</footer>
);
}在这个组件中,我们可以看到 isOpen 条件为 true 时渲染的 JSX 可以被提取为自己的组件。让我们一步步来实现这个过程。
步骤 1:创建新组件
首先,我们从 Footer 组件中剪切相应的 JSX,并创建一个新的 Order 组件:
function Order() {
return (
<div className="order">
<p>We're open until {closeHour}:00. Come visit us or order online.</p>
<button className="btn">Order</button>
</div>
);
}步骤 2:修改原组件以使用新组件
然后,我们更新 Footer 组件以使用新创建的 Order 组件:
function Footer() {
const hour = new Date().getHours();
const openHour = 20;
const closeHour = 22;
const isOpen = hour >= openHour && hour <= closeHour;
return (
<footer className="footer">
{isOpen ? (
<Order />
) : (
<p>
We're happy to welcome you between {openHour}:00 and {closeHour}
</p>
)}
</footer>
);
}步骤 3:解决数据访问问题
但是,我们立即遇到了一个问题 – 新的 Order 组件无法访问 closeHour 变量,因为该变量是在 Footer 组件中定义的。这就是 props 发挥作用的地方!
步骤 4:使用 Props 传递数据
我们需要将 closeHour 作为 prop 从 Footer 组件传递到 Order 组件:
function Footer() {
const hour = new Date().getHours();
const openHour = 20;
const closeHour = 22;
const isOpen = hour >= openHour && hour <= closeHour;
return (
<footer className="footer">
{isOpen ? (
<Order closeHour={closeHour} />
) : (
<p>
We're happy to welcome you between {openHour}:00 and {closeHour}
</p>
)}
</footer>
);
}
function Order(props) {
return (
<div className="order">
<p>We're open until {props.closeHour}:00. Come visit us or order online.</p>
<button className="btn">Order</button>
</div>
);
}现在,我们的 Order 组件可以通过 props.closeHour 访问关闭时间了.
理解 Props
Props(属性)是 React 中父组件向子组件传递数据的方式。它们非常类似于函数参数,这也是为什么我们可以将它们视为将参数传递给函数的方式。
在我们的例子中:
Footer是父组件Order是子组件closeHour是我们想要传递的数据- 我们通过
<Order closeHour={closeHour} />传递数据 - 在
Order组件中,我们通过props.closeHour访问这个数据
组件结构可视化
作为一个练习,尝试在纸上画出整个应用程序的组件结构是一个很好的做法。对于这个特定的项目,组件结构看起来像这样:
App
├── Header
├── Menu
│ └── Pizza (multiple instances)
└── Footer
└── Order (conditionally rendered)通过可视化组件结构,您可以更好地理解数据是如何在应用程序中流动的,以及各个组件是如何相互关联的。
何时提取组件
以下是一些何时应该考虑提取组件的指导原则:
- 当一个组件变得过大或复杂时 – 如果您需要花费太多时间理解一个组件的功能,可能是时候分解它了
- 当一部分 UI 被重复使用时 – 不要在多个地方复制相同的 JSX,而应该提取一个可重用的组件
- 当一部分 UI 有其自己的状态或行为时 – 如果 UI 的一部分有自己的状态管理或行为逻辑,它可能是一个很好的提取候选
完整代码(点击展开)
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
const pizzaData = [
{
name: "Focaccia",
ingredients: "Bread with italian olive oil and rosemary",
price: 6,
photoName: "pizzas/focaccia.jpg",
soldOut: false,
},
{
name: "Pizza Margherita",
ingredients: "Tomato and mozarella",
price: 10,
photoName: "pizzas/margherita.jpg",
soldOut: false,
},
{
name: "Pizza Spinaci",
ingredients: "Tomato, mozarella, spinach, and ricotta cheese",
price: 12,
photoName: "pizzas/spinaci.jpg",
soldOut: false,
},
{
name: "Pizza Funghi",
ingredients: "Tomato, mozarella, mushrooms, and onion",
price: 12,
photoName: "pizzas/funghi.jpg",
soldOut: false,
},
{
name: "Pizza Salamino",
ingredients: "Tomato, mozarella, and pepperoni",
price: 15,
photoName: "pizzas/salamino.jpg",
soldOut: true,
},
{
name: "Pizza Prosciutto",
ingredients: "Tomato, mozarella, ham, aragula, and burrata cheese",
price: 18,
photoName: "pizzas/prosciutto.jpg",
soldOut: false,
},
];
function App() {
return (
<div className="container">
<Header />
<Menu />
<Footer />
</div>
);
}
function Header() {
const style = {};
return (
<header className="header">
<h1 style={style}>Fast React Pizza Co.</h1>
</header>
);
}
function Menu() {
const pizzas = pizzaData;
// const pizzas = [];
const numPizzas = pizzas.length;
return (
<main className="menu">
<h2>Our Menu</h2>
{numPizzas > 0 ? (
<ul className="pizzas">
{pizzas.map((pizza) => (
<Pizza pizzaObj={pizza} key={pizza.name} />
))}
</ul>
) : (
<p>We're still working on our menu. Please come back later</p>
)}
{/* <Pizza
name="Pizza Spinaci"
ingredient="Tomato, mozarella, spinach, and ricotta cheese"
photoName="pizzas/spinaci.jpg"
price={10}
/>
<Pizza
name="Pizza Funghi"
ingredient="Tomato, mushrooms"
price={12}
photoName="pizzas/funghi.jpg"
/> */}
</main>
);
}
function Pizza(props) {
console.log(props);
if (props.pizzaObj.soldOut) {
return null;
}
return (
<li className="pizza">
<img src={props.pizzaObj.photoName} alt={props.pizzaObj.name}></img>
<div>
<h3>{props.pizzaObj.name}</h3>
<p>{props.pizzaObj.ingredients}</p>
<span>{props.pizzaObj.price}</span>
</div>
</li>
);
}
function Footer() {
const hour = new Date().getHours();
const openHour = 20;
const closeHour = 22;
const isOpen = hour >= openHour && hour <= closeHour;
console.log(isOpen);
return (
<footer className="footer">
{isOpen ? (
<Order closeHour={closeHour} />
) : (
<p>
We're happy to welcome you between {openHour}:00 and {closeHour}
</p>
)}
</footer>
);
}
function Order(props) {
return (
<div className="order">
<p>
We're open until {props.closeHour}:00. Come visit us or order online.
</p>
<button className="btn">Order</button>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

发表回复