从redux react typescript筛选数组对象

从redux react typescript筛选数组对象,typescript,redux,filter,react-redux,include,Typescript,Redux,Filter,React Redux,Include,我正在映射一个由redux state获得的数组对象。我需要创建一个搜索过滤器,根据键名称过滤数组。我正在和这个过滤器抗争,它就是不起作用,我正在尝试各种各样的方法。 items包含数组对象,filtered包含输入中键入的文本,我可以从redux状态获取所有这些文本,并使用mapstatetops将它们保存到props 声明: items: [{name: "bla"}, {..}, {..}] (50 objects in array) filtered: "t

我正在映射一个由redux state获得的数组对象。我需要创建一个搜索过滤器,根据键
名称
过滤数组。我正在和这个过滤器抗争,它就是不起作用,我正在尝试各种各样的方法。
items
包含数组对象,
filtered
包含输入中键入的文本,我可以从redux状态获取所有这些文本,并使用
mapstatetops将它们保存到props

声明:

items: [{name: "bla"}, {..}, {..}] (50 objects in array)
filtered: "test"
减速器:

case SEARCH:
      return {
        ...state,
        filtered: action.value
      };
组成部分:

    const Tournaments = (props: TournamentInterface) => {
      const {
        items,
        filtered
      } = props;
    
    const mapStateToProps = (state: { tournaments: TournamentInterface }) => {
      return {
        items: state.tournaments.items,
        loading: state.tournaments.loading,
        error: state.tournaments.error,
        filtered: state.tournaments.filtered
      };
    };
    
        return (
         <ItemContainer>
        {items &&
                !loading &&
                items
                  .filter((item: any) => item.name.toLowerCase() === filtered)
                  .map(
                    (
                      item: {
                        name: string;
                        game: React.ReactNode;
                        participants: {
                          current: React.ReactNode;
                          max: React.ReactNode;
                        };
                        startDate: Date;
                      },
                      index: number
                    ) => (
                      <div className="item" key={index}>
                        <H6>{item.name}</H6>
                       </div>
                    )
                  )}
         </ItemContainer>
          );
};
const Tournaments=(道具:TournamentInterface)=>{
常数{
项目,
过滤
}=道具;
常量mapStateToProps=(状态:{tournaments:TournamentInterface})=>{
返回{
项目:州。锦标赛。项目,
加载:state.tournaments.load,
错误:state.tournaments.error,
过滤:state.tournaments.filtered
};
};
返回(
{项目&&
!加载&&
项目
.filter((项:任意)=>item.name.toLowerCase()==已筛选)
.地图(
(
项目:{
名称:字符串;
游戏:React.React节点;
与会者:{
当前:React.ReactNode;
max:React.ReactNode;
};
起始日期:日期;
},
索引:编号
) => (
{item.name}
)
)}
);
};

尝试在redux中进行筛选

case SEARCH:
 return {
   items: state.items.filter((item: any) => item.name.toLowerCase().includes(filtered.toLowerCase())),
   filtered: action.value
 };

这里有很多东西要打开。您不需要在
.map
回调中指定类型,因为如果数组本身键入正确,则可以知道该类型。但显然不是。所以我们需要修正你的类型

你还没有包括你的
锦标赛接口
类型,但我可以通过反向工作了解它是什么。由于这些项来自Redux,因此属性需要比
ReactNode
更具体的类型,因为可分配给
ReactNode
的某些类型不可序列化。出于同样的原因,您的日期应该存储为原始时间戳,而不是
Date
对象

试试这个:

interface Item {
  name: string;
  game: string;
  participants: {
    current: number;
    max: number;
  };
  startDate: number;
}

interface TournamentInterface {
  items: Item[];
  loading: boolean;
  error?: string | null;
  filtered: string;
}

type RootState = {
  tournaments: TournamentInterface;
};


我在某个地方读到,最好不要直接在redux中过滤状态,而是在组件中过滤。是的,当我尝试更改状态中的items数组时,不会返回显示所有对象,因为它已被过滤

我完全同意第一句话,第二句是为什么。如果过滤
属性,则会丢失项。如果将过滤后的数组存储在单独的属性中,则存在重复数据


您可以在选择器函数中执行筛选,并在mapStateToProps中使用该函数。这将逻辑移出组件,并进入选择器,您可以在需要时重新用于其他组件HMR

我喜欢@HMR的建议。可以使用创建仅在状态更改时返回新值的记忆选择器。我正在使用你的过滤功能从评论

import { createSelector } from "reselect";

const selectFilteredItems = createSelector(
  // input selectors
  (state: RootState) => state.tournaments.items,
  (state: RootState) => state.tournaments.filtered,
  // combiner - types here are inferred correctly
  (items, filtered) =>
    items.filter((item) =>
      item.name.toLowerCase().includes(filtered.toLowerCase())
    )
);

我将使用
useSelector
而不是
mapstatetops
,因为这是最新的、最新的方法。我们可以使用
createSelectorHook
实用程序,以便自动推断
RootState
类型

import { createSelectorHook } from "react-redux";

const useSelector = createSelectorHook<RootState>();
从“react redux”导入{createSelectorHook};
const useSelector=createSelectorHook();
const锦标赛=()=>{
const load=useSelector((state)=>state.tournaments.load);
const filteredItems=useSelector(selectFilteredItems);
返回(
{加载(
) : (
filteredItems.map((项目,索引)=>(
{item.name}
开始:{新日期(item.startDate).toDateString()}
))
)}
);
};

oh-hey我刚刚添加了includes(),它可以工作:.filter((item:any)=>item.name.toLowerCase().includes(filtered)).map()。但是如果你能找到一个更好的方法来创建它,请发布一个答案。你可以在选择器函数中进行筛选,并在mapStateToProps中使用它。这将逻辑从组件中移出,并进入一个选择器,您可以在需要时为其他组件重复使用。嘿,我正在为您写一个答案,但如果您可以发布您的
TournamentInterface
,我可以确保我的理解正确。我在某个地方读到,最好不要直接在redux中过滤状态,而是在组件中过滤状态。是的,当我尝试更改状态中的items数组时,不会返回显示所有对象,因为它已被过滤。但这是个好主意。事实上,如果项目在其他组件中不可用,您不需要在redux中保留它们,也可以使用筛选键。(阅读关于“您不需要redux”的文章)。相反,存储在组件状态,并在需要的地方传递。我不希望使用redux,但这是项目的一个要求。
const Tournaments = () => {
  const loading = useSelector((state) => state.tournaments.loading);
  const filteredItems = useSelector(selectFilteredItems);

  return (
    <ItemContainer>
      {loading ? (
        <Spinner />
      ) : (
        filteredItems.map((item, index) => (
          <div className="item" key={index}>
            <h6>{item.name}</h6>
            <div>Started: {new Date(item.startDate).toDateString()}</div>
          </div>
        ))
      )}
    </ItemContainer>
  );
};