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

React Native中如何用Redux Hooks结合搜索栏实现FlatList搜索?

解决React Native + Redux Hooks搜索FlatList的问题

我帮你梳理下当前代码的核心问题,然后给出两种可行的解决方案,你可以根据自己的场景选择:

问题根源

你当前的代码里,每次搜索都是直接基于Redux store中**已经过滤后的parsedContacts**进行二次过滤——这就导致第一次搜索后,原始的全量联系人数据被覆盖了,后续搜索只能基于上一次的结果缩小范围,完全没法回到全量数据,自然就无法正确更新搜索结果。另外,还要确保你的Redux reducer是正确处理状态更新的(比如有没有做不可变更新)。


方案一:在Redux中分离原始数据与过滤结果

适合需要在多个组件共享过滤后联系人数据的场景,我们可以在Redux的user slice里新增两个状态:

  • allContacts:存储原始全量联系人数据,永远不修改
  • filteredContacts:存储实时过滤后的结果

1. 调整Redux Slice(示例)

// src/slices/userSlice.js
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  allContacts: null, // 原始全量数据
  filteredContacts: null, // 过滤后的数据
};

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    // 设置原始全量联系人,同时初始化过滤结果
    setAllContacts: (state, action) => {
      state.allContacts = action.payload;
      state.filteredContacts = action.payload;
    },
    // 更新过滤后的联系人
    setFilteredContacts: (state, action) => {
      state.filteredContacts = action.payload;
    },
  },
});

export const { setAllContacts, setFilteredContacts } = userSlice.actions;
export default userSlice.reducer;

2. 修改Contacts组件代码

import { useDispatch, useSelector } from 'react-redux';
import { useEffect } from 'react';
import { View, StatusBar, FlatList, ActivityIndicator } from 'react-native';
import SearchBar from 'react-native-dynamic-searchbar';
import ContactListItem from './ContactListItem'; // 你的自定义组件
import { setFilteredContacts } from '../slices/userSlice';
import styles from './ContactsStyles'; // 你的样式文件

const Contacts = () => { 
  const dispatch = useDispatch(); 
  // 获取Redux中的原始数据和过滤后的数据
  const allContacts = useSelector(state => state.user.allContacts); 
  const filteredContacts = useSelector(state => state.user.filteredContacts); 

  const renderContacts = ({ item }) => { 
    return ( 
      <ContactListItem 
        name={item.full_name} 
        phone={item.phone} 
        isRegisteredUser={item.id !== 0} 
      /> 
    ) 
  } 

  const handleFilter = (input) => { 
    if (!allContacts) return;
    // 基于原始全量数据过滤,统一转小写实现不区分大小写搜索
    const filtered = allContacts.filter(contact => 
      contact.full_name.toLowerCase().includes(input.toLowerCase())
    );
    dispatch(setFilteredContacts(filtered)); 
  } 

  // 当原始数据更新时,同步重置过滤结果
  useEffect(() => {
    if (allContacts && !filteredContacts) {
      dispatch(setFilteredContacts(allContacts));
    }
  }, [allContacts, filteredContacts, dispatch]);

  // 加载状态处理
  if (!filteredContacts) { 
    return (
      <View style={styles.loading}>
        <ActivityIndicator size="large" color="#EE578D" />
      </View>
    );
  } 

  return ( 
    <View style={styles.container}>
      <StatusBar /> 
      <View style={styles.topMargin} />
      <View style={styles.header}> 
        <SearchBar 
          iconColor="#EE578D" 
          placeholder="Search Here..." 
          onChangeText={handleFilter} 
          // 清空搜索框时恢复全量数据
          onClear={() => dispatch(setFilteredContacts(allContacts))}
        /> 
      </View> 
      <FlatList 
        data={filteredContacts} 
        renderItem={renderContacts} 
        initialNumToRender={5} 
        maxToRenderPerBatch={10} 
        windowSize={10} 
        // 优先用数据的唯一ID作为key,避免index导致的列表复用问题
        keyExtractor={(item) => item.id?.toString() || Math.random().toString()}
      /> 
    </View> 
  );
};

export default Contacts;

方案二:组件内用useState维护过滤结果

如果不需要在其他组件共享过滤后的联系人数据,这个方案更轻量,不需要修改Redux结构:

import { useDispatch, useSelector } from 'react-redux';
import { useState, useEffect } from 'react';
import { View, StatusBar, FlatList, ActivityIndicator } from 'react-native';
import SearchBar from 'react-native-dynamic-searchbar';
import ContactListItem from './ContactListItem';
import styles from './ContactsStyles';

const Contacts = () => { 
  const dispatch = useDispatch(); 
  const allContacts = useSelector(state => state.user.parsedContacts); 
  // 组件内维护过滤后的列表状态
  const [filteredContacts, setFilteredContacts] = useState(allContacts); 

  const renderContacts = ({ item }) => { 
    return ( 
      <ContactListItem 
        name={item.full_name} 
        phone={item.phone} 
        isRegisteredUser={item.id !== 0} 
      /> 
    ) 
  } 

  const handleFilter = (input) => { 
    if (!allContacts) return;
    const filtered = allContacts.filter(contact => 
      contact.full_name.toLowerCase().includes(input.toLowerCase())
    );
    setFilteredContacts(filtered); 
  } 

  // 原始数据更新时同步重置过滤结果
  useEffect(() => {
    setFilteredContacts(allContacts);
  }, [allContacts]);

  if (!filteredContacts) { 
    return (
      <View style={styles.loading}>
        <ActivityIndicator size="large" color="#EE578D" />
      </View>
    );
  } 

  return ( 
    <View style={styles.container}>
      <StatusBar /> 
      <View style={styles.topMargin} />
      <View style={styles.header}> 
        <SearchBar 
          iconColor="#EE578D" 
          placeholder="Search Here..." 
          onChangeText={handleFilter} 
          onClear={() => setFilteredContacts(allContacts)}
        /> 
      </View> 
      <FlatList 
        data={filteredContacts} 
        renderItem={renderContacts} 
        initialNumToRender={5} 
        maxToRenderPerBatch={10} 
        windowSize={10} 
        keyExtractor={(item) => item.id?.toString() || Math.random().toString()}
      /> 
    </View> 
  );
};

export default Contacts;

额外优化点

  1. 避免用index作为key:尽量使用数据本身的唯一ID(比如item.id),防止FlatList在数据变化时出现复用错误。
  2. 不区分大小写搜索:把搜索关键词和联系人名称都转成小写,提升用户体验。
  3. 加载状态处理:在联系人数据未加载完成时显示加载指示器,避免空列表或报错。

内容的提问来源于stack exchange,提问作者Mr. Robot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 08:57:42