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

React+MUI+Redux项目中如何实现Firebase自动补全搜索栏?

实现Firestore搜索功能到你的React+MUI Navbar

Hey there! I see you're building a full-stack app with React, MUI, Redux, and Firestore—great stack choice! Let's walk through adding that search bar functionality to your Navbar, so you can search document names or values in your Firestore collections.

First, a quick cleanup note: I noticed you have duplicate imports for TextField in your Navbar.js—you can remove one instance to keep your code tidy.


Step 1: Set up Firestore access

First, make sure you've initialized Firebase in your project. Create a utility file (like firebase.js) to handle Firebase setup, or add this directly to your project:

import firebase from 'firebase/app';
import 'firebase/firestore';

// Replace with your Firebase config
const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID"
};

firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
export default db;

Step 2: Update your Navbar component with search logic

Let's modify your existing Navbar.js to add search submission, Firestore queries, and integrate with Redux to store results.

First, import your Firestore reference and a search icon:

import db from '../../firebase'; // Adjust path to your firebase.js
import SearchIcon from '@material-ui/icons/Search';

Next, add these methods inside your Navbar class to handle search queries and key presses:

// Handle Firestore search when button is clicked
handleSearch = async () => {
  const { query } = this.state;
  if (!query.trim()) return; // Skip empty searches

  try {
    // Replace 'your-collection-name' with your actual Firestore collection
    const collectionRef = db.collection('your-collection-name');

    // Option 1: Search for documents where ID matches the query (partial match)
    const idQuery = collectionRef
      .where(firebase.firestore.FieldPath.documentId(), '>=', query)
      .where(firebase.firestore.FieldPath.documentId(), '<=', query + '\uf8ff');

    // Option 2: Search for a specific field (e.g., 'name' or 'title'—replace with your field)
    const fieldQuery = collectionRef
      .where('name', '>=', query)
      .where('name', '<=', query + '\uf8ff');

    // Run both queries and combine results (avoid duplicates)
    const [idResults, fieldResults] = await Promise.all([idQuery.get(), fieldQuery.get()]);
    const combinedResults = [];
    const seenIds = new Set();

    idResults.forEach(doc => {
      if (!seenIds.has(doc.id)) {
        seenIds.add(doc.id);
        combinedResults.push({ id: doc.id, ...doc.data() });
      }
    });

    fieldResults.forEach(doc => {
      if (!seenIds.has(doc.id)) {
        seenIds.add(doc.id);
        combinedResults.push({ id: doc.id, ...doc.data() });
      }
    });

    // Send results to Redux store
    this.props.dispatchSearchResults(combinedResults);
  } catch (error) {
    console.error('Search error:', error);
    // Optional: Dispatch an error action to Redux for user feedback
  }
};

// Trigger search when Enter key is pressed
handleSearchKeyPress = (e) => {
  if (e.key === 'Enter') this.handleSearch();
};

Now update your search bar section to include a search button and key press handler:

// Inside the authenticated Fragment, replace your existing TextField with this:
<TextField 
  name="search" 
  label="Cerca" 
  value={this.state.query} 
  onChange={this.searchChange}
  onKeyPress={this.handleSearchKeyPress}
  variant="outlined"
  size="small"
  style={{ marginRight: 8 }}
/>
<MyButton 
  onClick={this.handleSearch}
  tip="Search"
>
  <SearchIcon />
</MyButton>

Step 3: Add Redux Actions & Reducer to manage search results

Since you're using Redux, let's create actions and a reducer to store search results so other components can access them.

Create search actions (e.g., actions/searchActions.js)

export const SET_SEARCH_RESULTS = 'SET_SEARCH_RESULTS';
export const CLEAR_SEARCH_RESULTS = 'CLEAR_SEARCH_RESULTS';

export const setSearchResults = (results) => ({
  type: SET_SEARCH_RESULTS,
  payload: results
});

export const clearSearchResults = () => ({
  type: CLEAR_SEARCH_RESULTS
});

Create search reducer (e.g., reducers/searchReducer.js)

import { SET_SEARCH_RESULTS, CLEAR_SEARCH_RESULTS } from '../actions/searchActions';

const initialState = {
  results: [],
  error: null
};

const searchReducer = (state = initialState, action) => {
  switch(action.type) {
    case SET_SEARCH_RESULTS:
      return {
        ...state,
        results: action.payload,
        error: null
      };
    case CLEAR_SEARCH_RESULTS:
      return {
        ...state,
        results: [],
        error: null
      };
    default:
      return state;
  }
};

export default searchReducer;

Add reducer to your root reducer

Update your root reducer to include the search state:

// In rootReducer.js
import { combineReducers } from 'redux';
import userReducer from './userReducer';
import uiReducer from './uiReducer';
import searchReducer from './searchReducer'; // Import new reducer

export default combineReducers({
  user: userReducer,
  UI: uiReducer,
  search: searchReducer // Add to store
});

Connect actions to your Navbar

Update your Navbar.js to include the search action and state:

import { setSearchResults } from '../../actions/searchActions'; // Import action

// Update mapStateToProps to get search results
const mapStateToProps = state =>({
  authenticated: state.user.authenticated,
  user: state.user,
  game: state.UI,
  search: state.search // Add search state
})

// Add mapDispatchToProps to send results to Redux
const mapDispatchToProps = (dispatch) => ({
  dispatchSearchResults: (results) => dispatch(setSearchResults(results))
});

// Update connect call
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Navbar))

Step 4: Display search results

Add a dropdown to your Navbar to show search results using MUI's Popover:

First, update your component state:

this.state = {
  open: false,
  game:'ygo',
  query:'',
  searchPopoverOpen: false,
  anchorEl: null
};

Add popover handlers:

handlePopoverOpen = (event) => {
  this.setState({ anchorEl: event.currentTarget, searchPopoverOpen: true });
};

handlePopoverClose = () => {
  this.setState({ searchPopoverOpen: false, anchorEl: null });
};

Add the Popover component after your search button:

<Popover
  open={this.state.searchPopoverOpen}
  anchorEl={this.state.anchorEl}
  onClose={this.handlePopoverClose}
  anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
>
  <List style={{ minWidth: 300 }}>
    {this.props.search.results.length === 0 ? (
      <ListItem>
        <ListItemText primary="No results found" />
      </ListItem>
    ) : (
      this.props.search.results.map((result) => (
        <ListItem 
          key={result.id} 
          component={Link} 
          to={`/post/${result.id}`} // Replace with your detail page route
          onClick={this.handlePopoverClose}
        >
          <ListItemText primary={result.name || result.title} />
          {/* Add more document details here if needed */}
        </ListItem>
      ))
    )}
  </List>
</Popover>

Key Optimization Tips

  • Throttle Real-Time Search: If you want search to trigger as the user types, use Lodash's _.throttle to limit Firestore requests (e.g., only run the query after 300ms of inactivity).
  • Firestore Indexes: If you get an index error in your console, follow the provided link to create the required index automatically.
  • Loading State: Add a loading spinner while the search runs to improve UX—add a loading field to your search reducer and update it before/after the query.
  • Security Rules: Ensure your Firestore rules allow authenticated users to read the collection:
    match /your-collection-name/{document} {
      allow read: if request.auth != null;
    }
    

内容的提问来源于stack exchange,提问作者Loki00

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:56:48