从redux react typescript筛选数组对象
我正在映射一个由redux state获得的数组对象。我需要创建一个搜索过滤器,根据键从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
名称
过滤数组。我正在和这个过滤器抗争,它就是不起作用,我正在尝试各种各样的方法。
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>
);
};