React开发求助:实现点击锦标赛项后显示被点击内容
Hey there! I see you're stuck getting the clicked tournament name from your Tournaments.js component to show up in templates.js—this is a super common component communication problem in React, and we can fix it easily with a couple of approachable solutions. Let's start with the most straightforward (and React-recommended) method: state lifting.
Solution 1: State Lifting (Best for Sibling/Close Parent-Child Components)
The core idea here is to move the "selected tournament" state up to a common parent component (like App.js), then pass a callback to Tournaments.js to update that state, and finally pass the state value to templates.js as a prop.
Step 1: Update the Common Parent Component (e.g., App.js)
First, we'll add the selected tournament state and a handler function to the parent that wraps both components:
import React, { Component } from "react"; import Tournaments from "./Tournaments"; import Templates from "./templates"; class App extends Component { constructor() { super(); this.state = { selectedTournament: "" // Stores the clicked tournament name }; } // Callback to update the selected tournament state handleTournamentSelect = (tournamentName) => { this.setState({ selectedTournament: tournamentName }); }; render() { return ( <div className="app-container"> {/* Pass the callback to Tournaments as a prop */} <Tournaments onSelectTournament={this.handleTournamentSelect} /> {/* Pass the selected name to Templates as a prop */} <Templates selectedTournament={this.state.selectedTournament} /> </div> ); } } export default App;
Step 2: Modify Tournaments.js to Trigger the Callback
Update your Tournaments component to call the parent's handler when a tournament is clicked. I'll also add the full fetch logic to load tournaments (since your snippet cut off):
import React, { Component } from "react"; const API = 'http://localhost:8080/api/tournaments'; class Tournaments extends Component { constructor() { super(); this.state = { tournaments: [] // Holds fetched tournament data }; } // Fetch tournaments when the component mounts componentDidMount() { fetch(API) .then(res => res.json()) .then(data => this.setState({ tournaments: data })) .catch(err => console.error("Failed to load tournaments:", err)); } render() { return ( <div className="tournaments-list"> <h2>Available Tournaments</h2> {this.state.tournaments.map(tournament => ( <div key={tournament.id} // Always use a unique key for list items onClick={() => this.props.onSelectTournament(tournament.name)} style={{ cursor: "pointer", padding: "8px", borderBottom: "1px solid #eee" }} > {tournament.name} </div> ))} </div> ); } } export default Tournaments;
Step 3: Update templates.js to Display the Selected Name
Finally, modify templates.js to receive and render the selected tournament name from props:
import React from "react"; // Functional component works here since we don't need internal state const Templates = (props) => { return ( <div className="templates-section"> <h2>Selected Tournament</h2> {props.selectedTournament ? ( <p>You've selected: <strong>{props.selectedTournament}</strong></p> ) : ( <p>Click a tournament from the list to select it</p> )} </div> ); }; export default Templates;
Solution 2: React Context (For Deeply Nested Components)
If your Tournaments and Templates are nested deeply with no close common parent, you can use React Context to share the selected state across your app. This is more scalable for larger apps, but state lifting is simpler for small use cases like this.
Quick Context Example (Optional)
- Create a Context file:
// TournamentContext.js import React, { createContext, Component } from "react"; export const TournamentContext = createContext(); export class TournamentProvider extends Component { state = { selectedTournament: "", setSelectedTournament: (name) => this.setState({ selectedTournament: name }) }; render() { return ( <TournamentContext.Provider value={this.state}> {this.props.children} </TournamentContext.Provider> ); } }
- Wrap your app with the provider in
index.js:
import { TournamentProvider } from "./TournamentContext"; ReactDOM.render( <TournamentProvider> <App /> </TournamentProvider>, document.getElementById("root") );
- Use the Context in Tournaments.js:
import { TournamentContext } from "./TournamentContext"; // Inside the render method of Tournaments: <TournamentContext.Consumer> {({ setSelectedTournament }) => ( <div onClick={() => setSelectedTournament(tournament.name)} // ... rest of your element styling > {tournament.name} </div> )} </TournamentContext.Consumer>
- Use the Context in templates.js:
import { TournamentContext } from "./TournamentContext"; const Templates = () => { return ( <TournamentContext.Consumer> {({ selectedTournament }) => ( <div> <h2>Selected Tournament</h2> <p>{selectedTournament || "No tournament selected"}</p> </div> )} </TournamentContext.Consumer> ); };
Key Notes
- Ensure your API returns tournaments with a unique
id(for the list key) and anamefield—adjust the code if your API uses different field names. - State lifting is the best starting point because it keeps your data flow predictable and easy to debug.
内容的提问来源于stack exchange,提问作者Cuzto

