React选择组件条件渲染问题:航班搜索输入值回传异常求助
Hey Joshua, let's break down what's causing your issues and fix them step by step!
The Core Problems in Your Current Code
- Duplicate Options: In
SearchCityList, you're rendering both<SelectCityLeaving>and<SelectCityGoing>for every flight result. That's why you see duplicate entries—each location is being rendered twice, once for each input. - No Context for Which Input is Active: Your
Formcomponent uses separateshowComponent/showComponent2states, but you're not passing information about which input was clicked to the search components. So when a user selects a location, the app doesn't know whether to send it to "Leaving From" or "Going To". - State Type Mismatch: In your
Formcomponent, you're settingLeavingFromandGoingToas arrays (this.setState({ GoingTo: [flights] });) but your inputs expect string values. This can cause unexpected rendering behavior.
Step-by-Step Fix
Let's refactor the code to resolve these issues:
1. Update the Form Component's State & Logic
Replace the separate showComponent states with a single activeInput state that tracks which input is open (either 'leaving', 'going', or null). This gives us clear context for the search flow.
class Form extends Component { state = { activeInput: null, // Tracks which input is open: 'leaving' | 'going' | null LeavingFrom: "", GoingTo: "" }; // Open the search panel and set which input is active openSearch = (inputType) => { this.setState({ activeInput: inputType }); }; closeSearch = () => { this.setState({ activeInput: null }); }; // Update the corresponding input value when a location is selected updateLocation = (inputType, value) => { this.setState({ [inputType]: value }); this.closeSearch(); // Close the panel after selection }; render() { const { activeInput, LeavingFrom, GoingTo } = this.state; return ( <div> <form className="form-fields container"> <div className="inputs"> <h1>Search for a flight!</h1> <div className="depart"> <input onClick={() => this.openSearch('leaving')} className="flight-search" placeholder="Leaving From" value={LeavingFrom} readOnly // Optional: prevent manual typing since we use the search panel /> <input type="date" /> </div> <div className="Returning"> <input onClick={() => this.openSearch('going')} className="flight-search" placeholder="Going To " value={GoingTo} readOnly /> <input type="date" placeholder="Returning" /> </div> </div> <button>Check Flights!</button> </form> {/* Only render SearchCity if activeInput is set */} {activeInput && ( <SearchCity activeInput={activeInput} closeSearch={this.closeSearch} updateLocation={this.updateLocation} /> )} </div> ); } } export default Form;
2. Simplify the SearchCity Component
We no longer need separate callbacks for each input—instead, we'll pass the activeInput and a single updateLocation callback. We'll also clean up the state and API call (note: I fixed the incomplete Axios syntax).
import Axios from 'axios'; class SearchCity extends Component { state = { search: "", flightSearch: [] }; // API call to fetch locations onSearchSubmission = async () => { try { const response = await Axios.get( // Replace with your actual API endpoint, including the search query `your-api-url?search=${this.state.search}`, { headers: { // Add your required headers here } } ); this.setState({ flightSearch: response.data.Places }); } catch (error) { console.error("Error fetching locations:", error); } }; // Trigger search when input changes (add debounce here for better performance!) handleSearchChange = (e) => { const searchValue = e.target.value; this.setState({ search: searchValue }, () => { if (searchValue.length > 2) { // Only search after 2 characters to reduce API calls this.onSearchSubmission(); } else { this.setState({ flightSearch: [] }); } }); }; closeSearch = () => { this.props.closeSearch(); this.setState({ search: "", flightSearch: [] }); // Reset search state }; render() { return ( <div className="container search-list"> <div> <i className="fas fa-times close-btn" onClick={this.closeSearch}></i> <input onChange={this.handleSearchChange} value={this.state.search} className="search-input" type="text" placeholder="Search Locations" /> <div className="search-scroll"> <SearchCityList flightSearch={this.state.flightSearch} activeInput={this.props.activeInput} updateLocation={this.props.updateLocation} /> </div> </div> </div> ); } } export default SearchCity;
3. Fix the SearchCityList & Create a Single SelectCity Component
Instead of two separate components for leaving/going, we'll use one component that uses the activeInput context to know which input to update. This eliminates duplicate options.
// Single SelectCity component instead of two separate ones function SelectCity({ flight, activeInput, updateLocation }) { const handleSelect = () => { // Pass the active input type and the selected location value updateLocation(activeInput, flight.Name); // Adjust flight.Name to match your API's location field }; return ( <div onClick={handleSelect} style={{ cursor: 'pointer', padding: '8px' }}> {flight.Name} {/* Use the correct field from your API response */} </div> ); } function SearchCityList({ flightSearch, activeInput, updateLocation }) { if (flightSearch.length === 0) { return <div>No locations found</div>; } const renderList = flightSearch.map((flight) => ( <SelectCity key={flight.PlaceId} // Use a unique ID from your API as the key flight={flight} activeInput={activeInput} updateLocation={updateLocation} /> )); return <div>{renderList}</div>; } export default SearchCityList;
Key Improvements Explained
- Single Active Input State: We now track exactly which input was opened, so the app knows where to send the selected location.
- No Duplicate Rendering: Only one
SelectCitycomponent per location result, so no duplicate options. - Unified Update Callback: A single
updateLocationfunction uses theactiveInputto update the correct state in the parentFormcomponent. - Cleaner State Management: Fixed the state type mismatch (using strings instead of arrays for location values).
- Better API Handling: Added basic error handling and a check to only search after the user types a few characters (you can add debouncing here for better performance).
内容的提问来源于stack exchange,提问作者JoshuaD

