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

React/Redux架构下基于Foursquare API实现本地存储最近搜索功能咨询

在React/Redux中实现搜索记录持久化与侧边栏展示

嘿,我来帮你一步步搞定这个需求!结合你的React/Redux项目,咱们可以分这几个核心部分来实现:

1. 设计Redux状态与Reducer管理搜索记录

首先,我们需要在Redux中维护搜索记录的状态,同时处理添加记录的逻辑(包括去重和数量限制)。

创建一个专门的reducer文件:

// src/reducers/searchHistory.js
const initialState = {
  history: []
};

const searchHistoryReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_SEARCH_HISTORY':
      // 去重:移除已有相同关键词的记录
      const uniqueHistory = state.history.filter(item => item.query !== action.payload.query);
      // 新记录放在最前面,同时限制最多10条
      const updatedHistory = [action.payload, ...uniqueHistory].slice(0, 10);
      return { ...state, history: updatedHistory };
    default:
      return state;
  }
};

export default searchHistoryReducer;

然后把这个reducer合并到你的rootReducer中:

// src/reducers/index.js
import { combineReducers } from 'redux';
import searchHistoryReducer from './searchHistory';
// 导入你的其他reducers

const rootReducer = combineReducers({
  searchHistory: searchHistoryReducer,
  // 其他reducer
});

export default rootReducer;

2. 实现localStorage持久化

Redux状态默认是内存级的,刷新就会丢失,所以我们需要把搜索记录持久化到localStorage。这里给你手动实现的方案:

// src/store.js
import { createStore } from 'redux';
import rootReducer from './reducers';

// 从localStorage加载初始状态
const loadSavedHistory = () => {
  try {
    const serializedData = localStorage.getItem('searchHistory');
    return serializedData ? { searchHistory: JSON.parse(serializedData) } : undefined;
  } catch (err) {
    // 读取失败时返回undefined,使用初始状态
    return undefined;
  }
};

// 保存状态到localStorage
const saveHistoryToLocal = (state) => {
  try {
    const serializedData = JSON.stringify(state.searchHistory);
    localStorage.setItem('searchHistory', serializedData);
  } catch (err) {
    // 忽略写入错误,避免影响应用
  }
};

// 创建store并加载持久化数据
const store = createStore(rootReducer, loadSavedHistory());

// 订阅状态变化,自动保存到localStorage
store.subscribe(() => {
  saveHistoryToLocal(store.getState());
});

export default store;

3. 开发侧边栏历史记录组件

接下来写一个侧边栏组件,连接Redux获取历史记录,渲染列表并处理点击跳转:

// src/components/SidebarHistory.js
import React from 'react';
import { connect } from 'react-redux';
import { useHistory } from 'react-router-dom';

const SidebarHistory = ({ historyRecords }) => {
  const routerHistory = useHistory();

  const handleRecordClick = (record) => {
    // 跳转到搜索结果页面,携带搜索参数
    routerHistory.push(
      `/search?query=${encodeURIComponent(record.query)}&location=${encodeURIComponent(record.location)}`
    );
  };

  return (
    <div className="sidebar-history">
      <h3>最近搜索</h3>
      {historyRecords.length === 0 ? (
        <p>暂无搜索记录</p>
      ) : (
        <ul>
          {historyRecords.map((record, idx) => (
            <li
              key={idx}
              onClick={() => handleRecordClick(record)}
              style={{ cursor: 'pointer', padding: '8px 0', borderBottom: '1px solid #eee' }}
            >
              {record.query} - {record.location}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

// 映射Redux状态到组件props
const mapStateToProps = (state) => ({
  historyRecords: state.searchHistory.history
});

export default connect(mapStateToProps)(SidebarHistory);

之后把这个组件嵌入到你的侧边栏布局里即可。

4. 搜索时添加记录到Redux

在你的搜索输入组件中,当用户执行搜索操作时,dispatch一个添加历史记录的action:

// src/components/SearchBar.js
import React, { useState } from 'react';
import { connect } from 'react-redux';

const SearchBar = ({ addSearchHistory }) => {
  const [query, setQuery] = useState('');
  const [location, setLocation] = useState('');

  const handleSearch = () => {
    // 这里调用Foursquare API获取搜索结果的逻辑...
    
    // 添加当前搜索到历史记录
    if (query && location) {
      addSearchHistory({ query, location });
    }
  };

  return (
    <div className="search-bar">
      <input
        type="text"
        placeholder="搜索餐饮..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <input
        type="text"
        placeholder="位置..."
        value={location}
        onChange={(e) => setLocation(e.target.value)}
      />
      <button onClick={handleSearch}>搜索</button>
    </div>
  );
};

// 映射dispatch到组件props
const mapDispatchToProps = (dispatch) => ({
  addSearchHistory: (record) => dispatch({ type: 'ADD_SEARCH_HISTORY', payload: record })
});

export default connect(null, mapDispatchToProps)(SearchBar);

5. 搜索结果页面接收参数并加载数据

最后,确保你的搜索结果页面能从URL参数中读取搜索条件,重新调用API获取结果:

// src/components/SearchResults.js
import React, { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';

const SearchResults = () => {
  const location = useLocation();
  const [venues, setVenues] = useState([]);

  useEffect(() => {
    const params = new URLSearchParams(location.search);
    const query = params.get('query');
    const locationParam = params.get('location');

    if (query && locationParam) {
      // 调用Foursquare API获取数据
      fetch(`https://api.foursquare.com/v2/venues/search?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&v=20240101&query=${query}&near=${locationParam}`)
        .then(res => res.json())
        .then(data => setVenues(data.response.venues))
        .catch(err => console.error('搜索失败:', err));
    }
  }, [location.search]);

  return (
    <div className="search-results">
      <h2>搜索结果</h2>
      {venues.map(venue => (
        <div key={venue.id} className="venue-item">
          <h3>{venue.name}</h3>
          <p>{venue.location.address}</p>
        </div>
      ))}
    </div>
  );
};

export default SearchResults;

几个关键注意点

  • 去重逻辑:避免重复的搜索记录,每次添加时先过滤掉相同关键词的条目
  • 数量限制:通过slice(0,10)确保最多只展示10条最近记录
  • 路由跳转:使用react-router的useHistory钩子实现页面跳转,参数用encodeURIComponent处理特殊字符
  • 异常处理:localStorage的读写操作要包裹try/catch,避免因权限问题导致应用崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:02:36