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

React跨组件传值问题:Navbar搜索框值无法共享至Shop页面

解决跨组件搜索状态共享与页面跳转触发API的方案

针对你的场景,下面提供几种实用的解决方案,覆盖不同需求场景:

方案1:通过URL参数传递搜索关键词(最推荐)

这种方式无需全局状态,依赖路由参数传递信息,支持刷新页面、书签保留搜索状态,是最直观可靠的方案。

实现步骤:

  1. NavSearch组件处理跳转:
    使用useNavigate跳转到Shop页面时,将搜索关键词作为URL的query参数传递

    import { useState, useNavigate } from 'react-router-dom';
    
    function NavSearch() {
      const navigate = useNavigate();
      const [keyword, setKeyword] = useState('');
    
      const handleSearch = () => {
        if (keyword.trim()) {
          // 对关键词编码避免特殊字符问题
          navigate(`/shop?search=${encodeURIComponent(keyword)}`);
        }
      };
    
      return (
        <div>
          <input
            type="text"
            value={keyword}
            onChange={(e) => setKeyword(e.target.value)}
            placeholder="搜索商品..."
          />
          <button onClick={handleSearch}>搜索</button>
        </div>
      );
    }
    
  2. Shop组件获取参数并触发API:
    使用useSearchParams监听URL参数变化,自动调用API

    import { useSearchParams, useEffect, useState } from 'react-router-dom';
    import { fetchProducts } from './your-api-module';
    
    function Shop() {
      const [searchParams] = useSearchParams();
      const [products, setProducts] = useState([]);
    
      useEffect(() => {
        const searchKeyword = searchParams.get('search');
        if (searchKeyword) {
          // 触发API调用
          fetchProducts(decodeURIComponent(searchKeyword))
            .then(res => setProducts(res.data))
            .catch(err => console.error('搜索失败:', err));
        }
      }, [searchParams]);
    
      return (
        <div className="shop-container">
          {products.length ? (
            products.map(product => (
              <div key={product.id} className="product-item">
                <h3>{product.name}</h3>
              </div>
            ))
          ) : (
            <p>暂无匹配商品</p>
          )}
        </div>
      );
    }
    

方案2:使用Context API实现全局状态共享

如果你的项目后续有多个组件需要共享搜索状态,或者不想暴露URL参数,可以用Context管理全局搜索状态。

实现步骤:

  1. 创建搜索Context:

    // SearchContext.js
    import { createContext, useContext, useState } from 'react';
    
    const SearchContext = createContext();
    
    export function SearchProvider({ children }) {
      const [searchKeyword, setSearchKeyword] = useState('');
    
      return (
        <SearchContext.Provider value={{ searchKeyword, setSearchKeyword }}>
          {children}
        </SearchContext.Provider>
      );
    }
    
    // 自定义Hook简化Context调用
    export function useSearch() {
      return useContext(SearchContext);
    }
    
  2. 在RootLayout中注入Provider:

    import { SearchProvider } from './SearchContext';
    import Navbar from './Navbar';
    import { Outlet } from 'react-router-dom';
    
    function RootLayout() {
      return (
        <SearchProvider>
          <Navbar />
          <Outlet />
        </SearchProvider>
      );
    }
    
  3. NavSearch组件更新全局状态并跳转:

    import { useState, useNavigate } from 'react-router-dom';
    import { useSearch } from './SearchContext';
    
    function NavSearch() {
      const navigate = useNavigate();
      const { setSearchKeyword } = useSearch();
      const [keyword, setKeyword] = useState('');
    
      const handleSearch = () => {
        if (keyword.trim()) {
          setSearchKeyword(keyword);
          navigate('/shop');
        }
      };
    
      return (
        <div>
          <input
            type="text"
            value={keyword}
            onChange={(e) => setKeyword(e.target.value)}
            placeholder="搜索商品..."
          />
          <button onClick={handleSearch}>搜索</button>
        </div>
      );
    }
    
  4. Shop组件监听全局状态触发API:

    import { useEffect, useState } from 'react';
    import { useSearch } from './SearchContext';
    import { fetchProducts } from './your-api-module';
    
    function Shop() {
      const { searchKeyword } = useSearch();
      const [products, setProducts] = useState([]);
    
      useEffect(() => {
        if (searchKeyword) {
          fetchProducts(searchKeyword)
            .then(res => setProducts(res.data))
            .catch(err => console.error('搜索失败:', err));
        }
      }, [searchKeyword]);
    
      return (
        <div className="shop-container">
          {products.length ? (
            products.map(product => (
              <div key={product.id} className="product-item">
                <h3>{product.name}</h3>
              </div>
            ))
          ) : (
            <p>暂无匹配商品</p>
          )}
        </div>
      );
    }
    

方案3:通过React Router的state传递参数(临时场景)

如果只是临时传递参数,不要求刷新页面保留状态,可以用路由跳转时的state属性:

实现步骤:

  1. NavSearch跳转时携带state:

    const handleSearch = () => {
      if (keyword.trim()) {
        navigate('/shop', { state: { searchKeyword: keyword } });
      }
    };
    
  2. Shop组件获取state并触发API:

    import { useLocation, useEffect, useState } from 'react-router-dom';
    
    function Shop() {
      const location = useLocation();
      const [products, setProducts] = useState([]);
    
      useEffect(() => {
        const searchKeyword = location.state?.searchKeyword;
        if (searchKeyword) {
          fetchProducts(searchKeyword)
            .then(res => setProducts(res.data))
            .catch(err => console.error('搜索失败:', err));
        }
      }, [location.state]);
    
      // 渲染逻辑...
    }
    

各方案优缺点对比

方案优点缺点
URL参数简单直观、支持刷新/书签、无全局状态依赖关键词暴露在URL中,不适合敏感信息
Context API全局状态共享、参数不暴露状态频繁更新可能导致不必要重渲染(可通过useMemo优化)
Router State参数不暴露、实现简单刷新页面后state丢失,仅适合临时传递

为什么你的自定义Hook会返回undefined?

自定义Hook如果只是内部用useState维护状态,每个组件调用该Hook时都会创建独立的状态实例。NavSearch和Shop是两个独立组件,它们调用的自定义Hook状态完全隔离,所以Shop中获取的是新的、未初始化的状态,自然返回undefined。要让自定义Hook实现状态共享,必须依赖Context、Redux等全局状态容器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 17:42:45