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

使用React Hooks开发会话级搜索历史页面的实现问题咨询

搜索历史功能实现方案

核心问题梳理

你现有代码存在两个核心问题:

  • 组件内声明的const history = []是普通局部变量,每次组件重渲染都会被重置,无法留存历史记录
  • debouncedTerm是Search组件的内部状态,无法直接在历史页组件中访问

实现步骤

1. 创建全局Context共享状态

我们用React Context实现会话级别的状态共享,页面刷新后数据自动清除,符合你的需求:

// SearchContext.js
import React, { createContext, useContext, useState } from 'react';

const SearchContext = createContext();

export const SearchProvider = ({ children }) => {
  // 存储搜索历史
  const [searchHistory, setSearchHistory] = useState([]);

  // 新增搜索记录的方法
  const addSearchHistory = (term) => {
    // 可选:去重,避免同一个关键词多次出现在历史里
    setSearchHistory(prev => {
      const filtered = prev.filter(item => item !== term);
      return [term, ...filtered]; // 最新搜索放在最前面
    });
  };

  return (
    <SearchContext.Provider value={{ searchHistory, addSearchHistory }}>
      {children}
    </SearchContext.Provider>
  );
};

// 自定义hook方便调用
export const useSearch = () => useContext(SearchContext);

然后在你的根组件(比如App.js)里包裹所有路由组件:

import { SearchProvider } from './SearchContext';

function App() {
  return (
    <SearchProvider>
      {/* 你的路由/页面组件放在这里 */}
    </SearchProvider>
  );
}

2. 改造Search组件,记录搜索历史

在debouncedTerm触发搜索的useEffect里调用新增历史的方法即可:

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useSearch } from './SearchContext'; // 引入自定义hook

const Search = () => {
  const [term, setTerm] = useState('');
  const [debouncedTerm, setDebouncedTerm] = useState(term);
  const [results, setResults] = useState([]);
  const { addSearchHistory } = useSearch(); // 获取新增历史的方法

  useEffect(() => {
    const timerId = setTimeout(() => {
      setDebouncedTerm(term);
    }, 1000);

    return () => {
      clearTimeout(timerId);
    };
  }, [term]);

  useEffect(() => {
    const search = async () => {
      const { data } = await axios.get('http://hn.algolia.com/api/v1/search?', {
        params: {
          query: debouncedTerm,
        },
      });
      setResults(data.hits);
      // 搜索成功后新增到历史记录
      addSearchHistory(debouncedTerm);
    };
    if (debouncedTerm) {
      search();
    }
  }, [debouncedTerm, addSearchHistory]);

  // 后面的渲染逻辑保持不变即可
  const renderedResults = results.map((result) => {
    return (
      <div key={result.objectID} className="item">
        <div className="right floated content">
          <a className="ui button" href={result.url}>
            Go
          </a>
        </div>
        <div className="content">
          <div className="header">{result.title}</div>
        </div>
      </div>
    );
  });

  return (
    <div>
      <div className="ui form">
        <div className="field">
          <label>Hacker News Search:</label>
          <input
            value={term}
            onChange={(e) => setTerm(e.target.value)}
            className="input"
          />
        </div>
      </div>
      <div className="ui celled list">{renderedResults}</div>
    </div>
  );
};

export default Search;

3. 实现历史页组件

直接从Context中获取历史列表渲染即可:

// SearchHistory.js
import React from 'react';
import { useSearch } from './SearchContext';

const SearchHistory = () => {
  const { searchHistory } = useSearch();

  return (
    <div className="ui container">
      <h3>最近搜索记录</h3>
      {searchHistory.length === 0 ? (
        <p>暂无搜索记录</p>
      ) : (
        <div className="ui list">
          {searchHistory.map((term, index) => (
            <div key={index} className="item">
              {term}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

export default SearchHistory;

4. 配置路由实现页面导航

用React Router配置两个页面的路由,加简单导航栏即可:

// App.js 完整示例
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { SearchProvider } from './SearchContext';
import Search from './Search';
import SearchHistory from './SearchHistory';

function App() {
  return (
    <SearchProvider>
      <Router>
        <div className="ui menu">
          <Link to="/" className="item">搜索页</Link>
          <Link to="/history" className="item">搜索历史</Link>
        </div>
        <div className="ui container">
          <Routes>
            <Route path="/" element={<Search />} />
            <Route path="/history" element={<SearchHistory />} />
          </Routes>
        </div>
      </Router>
    </SearchProvider>
  );
}

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 20:45:04