You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

  1. 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.
  2. No Context for Which Input is Active: Your Form component uses separate showComponent/showComponent2 states, 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".
  3. State Type Mismatch: In your Form component, you're setting LeavingFrom and GoingTo as 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 SelectCity component per location result, so no duplicate options.
  • Unified Update Callback: A single updateLocation function uses the activeInput to update the correct state in the parent Form component.
  • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:32:29