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

详情页Search组件过滤失效:如何实现全局可用?

问题

我有三个React组件:Shows.jsx用于渲染全部演出列表、ProductDetails用于渲染单场演出详情,还有一个Search搜索组件实现按名称过滤演出的功能。目前Search组件在Shows页面使用时过滤功能正常,但在详情页使用时无法过滤,点击搜索后会渲染全部演出。

现有代码片段

Reducer代码

const initialState = {
  error: false,
  products: [],
  product: {},
  allProducts: [],
  filteredProducts: [],
};

const rootReducer = (state = initialState, action) => {
  const { type, payload } = action;
  switch (type) {
    case "GET_PRODUCTS":
      return {
        ...state,
        products: action.payload,
        allProducts: action.payload,
        filteredProducts: action.payload,
      };
      
    case "SEARCH":   
      console.log("search",  action.payload);
      return {
        ...state,
        products: action.payload,
      };
  }
};

Action代码

export const search = (name) => {
  return async function (dispatch) {
    try {
      let info = await axios.get("http://localhost:3001/products/?name=" + name);
      console.log('info.data en action', info.data);
      return dispatch({
        type: "SEARCH",
        payload: info.data,
      });
    } catch (error) {
      return "No pudimos encontrar ese producto";
    }
  };
}

Search组件代码

import React, { useState } from "react";
import "./SearchBar.css";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router-dom";
import * as actions from "../../redux/actions";

import Swal from 'sweetalert2';
import Error_Search from './Error_Search.jpg'

function Search() {
  const [suggestions, setSuggestions] = useState([]);
  const [name, setName] = useState("");
  const dispatch = useDispatch();
  const history = useHistory();
  const products = useSelector(state => state.products)

  const showAlertNoEnter=()=> {
    Swal.fire({
      imageUrl: Error_Search,
      imageHeight: 150,
      imageWidth: 200,
      imageAlt: 'Hubo un error en la búsqueda.',
      title: 'Buscador de Yazz', 
      html:'<h3>Por favor, ingresá un nombre</p>', 
      footer:'<p>Probá de nuevo.</p>'
    })
  }

  const showAlertNoName=()=> {
    Swal.fire({
      imageUrl: Error_Search,
      imageHeight: 150,
      imageWidth: 200,
      imageAlt: 'Hubo un error en la búsqueda.',
      title: 'Buscador de Yazz', 
      html:'<h3>Esa banda no tiene ningún show programado</p>', 
      footer:'<p>Probá con otra banda.</p>'
    })
  }

  function handleInputChange(e) {
    setName(e.target.value);
    let filtered = products.filter(
      (p) => p.name.toLowerCase().includes(e.target.value.toLowerCase())
    );
    setSuggestions(filtered);
  }

  function handleSearch(e) {
    e.preventDefault();
    if (!name) {
      showAlertNoEnter();
      return;
    }
    
    dispatch(actions.search(name));
    setName("");
    setSuggestions([]); 
    history.push("/shows");
  }

  function handleSuggestionClick(name) {
    dispatch(actions.search(name));
    setName("");
    setSuggestions([]); 
    history.push("/shows");
  }

  return (
    <div className="searchContainer">
      <div className="search_inputSuggest">
        <input
          id="search"
          className="searchBar"
          type="text"
          placeholder="Buscar por nombre"
          onChange={(e) => handleInputChange(e)}
          value={name}
        />
        <div className="search_suggestion_div">
          <datalist className="suggestionsList">
            {suggestions.slice(0, 10).map(s => (
              <option className="suggestionsList_item" key={s.id} onClick={() => handleSuggestionClick(s.name)}>
                {s.name}
              </option>
            ))}
          </datalist>
        </div>
      </div>
      <button className="btnSearch" onClick={(e) => handleSearch(e)}>
        Buscar
      </button>
    </div>
  );
}

export default Search;

解决方案

问题根源

  1. 本地过滤数据源错误:Search组件依赖products做过滤,但进入详情页后,products状态可能不再是全量演出数据,导致搜索建议和过滤逻辑失效。
  2. 搜索结果被覆盖:Shows页面可能每次挂载都会调用GET_PRODUCTS,将products重置为全量数据,覆盖搜索结果。
  3. Reducer状态管理混乱:SEARCH动作直接覆盖products,没有维护独立的过滤结果状态,导致页面渲染逻辑冲突。

修复步骤

1. 更换本地过滤的数据源为全量数据

修改Search组件,使用始终存储全量数据的allProducts做本地过滤:

// Search组件中替换数据源获取逻辑
const allProducts = useSelector(state => state.allProducts)

// 修改handleInputChange中的过滤逻辑
function handleInputChange(e) {
  setName(e.target.value);
  let filtered = allProducts.filter(
    (p) => p.name.toLowerCase().includes(e.target.value.toLowerCase())
  );
  setSuggestions(filtered);
}

2. 调整Reducer的SEARCH动作,维护独立过滤状态

修改Reducer,让SEARCH动作更新filteredProducts而非覆盖全量的products:

case "SEARCH":   
  console.log("search",  action.payload);
  return {
    ...state,
    filteredProducts: action.payload, // 单独存储过滤结果
  };

3. 修改Shows页面的渲染数据源

让Shows页面优先使用filteredProducts,无过滤结果时再用全量products:

// 在Shows组件中获取状态
const { products, filteredProducts } = useSelector(state => state);
// 确定最终渲染的演出列表
const showsToRender = filteredProducts.length > 0 ? filteredProducts : products;

4. 避免Shows页面重复获取全量数据

修改Shows组件的GET_PRODUCTS调用逻辑,仅当全量数据为空时发起请求:

// Shows组件的useEffect示例
useEffect(() => {
  if (products.length === 0) {
    dispatch(getProducts()); // 仅全量数据为空时获取
  }
}, [dispatch, products.length]);

5. 优化搜索错误提示逻辑

在Action的search函数中,针对空结果或请求失败触发对应提示:

export const search = (name) => {
  return async function (dispatch) {
    try {
      let info = await axios.get("http://localhost:3001/products/?name=" + name);
      console.log('info.data en action', info.data);
      
      if (info.data.length === 0) {
        Swal.fire({
          imageUrl: './Error_Search.jpg',
          imageHeight: 150,
          imageWidth: 200,
          imageAlt: 'Hubo un error en la búsqueda.',
          title: 'Buscador de Yazz', 
          html:'<h3>Esa banda no tiene ningún show programado</p>', 
          footer:'<p>Probá con otra banda.</p>'
        });
      }
      
      return dispatch({
        type: "SEARCH",
        payload: info.data,
      });
    } catch (error) {
      Swal.fire({
        imageUrl: './Error_Search.jpg',
        imageHeight: 150,
        imageWidth: 200,
        imageAlt: 'Hubo un error en la búsqueda.',
        title: 'Buscador de Yazz', 
        html:'<h3>No pudimos realizar la búsqueda</p>', 
        footer:'<p>Probá de nuevo más tarde.</p>'
      });
    }
  };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:00:16