React按对象索引渲染不同HTML及Meteor布局与标签错误问题
Hey there! Let's tackle your two issues step by step—first fixing that unclosed div error, then getting your auctions into a clean 3-column layout with React and Meteor.
一、修复未闭合div标签的HTML错误
First off, JSX is strict about tag closure—unlike plain HTML, you can't leave a <div> hanging without its corresponding </div>. Here are quick checks to fix this:
- Double-check all your opening
<div>tags to make sure each has a closing</div>. - For self-contained elements (like images, inputs), use self-closing syntax:
<img src="..." alt="..." />instead of<img src="..." alt="...">. - If you're using conditional rendering, ensure that every branch of your code returns properly closed elements.
二、实现3列响应式布局渲染Auctions集合
Forget manually tracking indexes to group items—CSS Grid is the easiest way to create a 3-column, auto-row layout. Here's a complete, fixed version of your App.js that implements this:
import React, { Component } from 'react'; import { withTracker } from 'meteor/react-meteor-data'; import { Auctions } from '/imports/api/auctions'; // Adjust this path to your actual collection import class App extends Component { render() { const { loading, auctions } = this.props; // Show loading state while data is fetching if (loading) return <div className="loading">Loading auctions...</div>; return ( <div className="auctions-container"> <h1>Active Auctions</h1> {/* Grid container for 3-column layout */} <div className="auctions-grid"> {auctions.map(auction => ( <div key={auction._id} className="auction-card"> <h3>{auction.title}</h3> <p>Current Price: ${auction.currentPrice}</p> <p>Ends: {new Date(auction.endDate).toLocaleString()}</p> {/* Add any other auction fields you need here */} </div> ))} </div> </div> ); } } // Wrap component with Tracker to fetch Meteor data export default withTracker(() => { // Subscribe to the auctions collection const subscription = Meteor.subscribe('auctions'); return { loading: !subscription.ready(), auctions: Auctions.find({}).fetch() // Fetch all auction documents }; })(App);
Add this CSS (either in a separate file or inline)
.auctions-grid { display: grid; grid-template-columns: repeat(3, 1fr); /* 3 equal-width columns */ gap: 1.5rem; /* Space between cards */ padding: 1rem; } .auction-card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 1rem; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .auctions-container { max-width: 1200px; margin: 0 auto; padding: 2rem; } .loading { text-align: center; padding: 2rem; font-size: 1.2rem; } /* Optional: Make it responsive for smaller screens */ @media (max-width: 768px) { .auctions-grid { grid-template-columns: repeat(2, 1fr); /* 2 columns on tablets */ } } @media (max-width: 480px) { .auctions-grid { grid-template-columns: 1fr; /* 1 column on mobile */ } }
Key details explained:
- withTracker: This connects your React component to Meteor's data layer, handling subscriptions and data fetching automatically. We check if the subscription is ready to show a loading state.
- CSS Grid: The
grid-template-columns: repeat(3, 1fr)rule creates 3 columns that take equal space in the container. Rows are added automatically as more auctions are loaded. - Key prop: Always include a unique
keywhen mapping over arrays in React—using the auction's_id(Meteor's auto-generated document ID) is perfect here.
If you really want to use index-based grouping (not recommended):
If you insist on grouping items by index (e.g., 3 items per row), you can split the auctions array into chunks first:
// Inside your render method const chunkedAuctions = []; for (let i = 0; i < auctions.length; i += 3) { chunkedAuctions.push(auctions.slice(i, i + 3)); } return ( <div className="auctions-container"> <h1>Active Auctions</h1> {chunkedAuctions.map((row, rowIndex) => ( <div key={rowIndex} className="auction-row"> {row.map(auction => ( <div key={auction._id} className="auction-card"> {/* Auction content */} </div> ))} </div> ))} </div> );
Then use Flexbox for the rows:
.auction-row { display: flex; gap: 1.5rem; margin-bottom: 1.5rem; justify-content: space-between; } .auction-card { flex: 1; /* Each card takes equal space in the row */ }
But again, CSS Grid is cleaner and requires less manual code!
内容的提问来源于stack exchange,提问作者Alan Ortega

