在React中过滤数据的最佳方式是什么?



我正在制作这个国家的餐馆目录。该API返回一个对象数组,每个对象由诸如restaurantName、restaurantLocation、restaurantPriceRange等字段组成。

我想创建一个过滤组件,它将把餐馆数组减少到只包含符合搜索条件的子集。我还需要通过URL传递过滤器值,我认为我应该使用路由器。

我正在考虑使用useState钩子存储初始数据集,然后使用useReducer存储活动过滤器选择和过滤后的餐厅集合的子集,只有那些匹配搜索条件的,但我觉得这是一个笨拙的解决方案,因为有效地我将复制整个餐厅集合的子集。

但是,如果我不使用useState将初始数据集存储在单独的对象中,则一旦应用了过滤器,所有不匹配的数据集将永远消失。

实现这一目标的最佳方法是什么?

免责声明:我知道如何在JavaScript中过滤数组,并充分了解诸如过滤器,映射,排序等功能。这个问题是关于React生态系统的,以及在React应用程序中构建我的代码的最干净、最简单和最好的方法是什么。我知道,当我为减速器编写代码时,我仍然需要在减速器中使用Array.prototype.filter。

你是在征求意见,所以这是我的意见。React状态(无论是useState还是useReducer)应该只用于有状态值——这些值会发生变化,并导致呈现的数据发生变化。过滤的餐馆列表不是一个有状态值。过滤器是一个有状态值,被过滤的列表是从该状态派生出来的。过滤列表应该是每次渲染时生成的const。如果在你的组件中有其他状态或道具的改变,而这些改变并不影响过滤列表,你可以使用useMemo钩子来记忆过滤列表,以防止不必要的重新计算。

伪代码

import React, {useMemo} from “react”;
import {useLocation} from “react-router-dom”;
export const MyComponent = ({restaurants}) => {
const location = useLocation();
const filteredRestaurants = useMemo( () => {
return restaurants.filter( /* some code */ );
}, [location, restaurants] ); //dependency on location and restaurants 
return (
<Wrapper>
<EditFiltersComponent />
<List>
{filteredRestaurants.map( restaurant => 
<Restaurant {...restaurant} />
)}
</List>
</Wrapper>
)
}

通常我们从props获取数据

const OurComponent = ({data, filter}) => { . . .

const { filter } = useParams(); // via query string

你也可以在这个组件中有过滤器输入字段,然后将它们的值存储在渲染器的本地状态中。

对于一个复杂的过滤器,最好有一个过滤器函数:

const filterFunc = ({address}) => {
address.toLowerCase().includes(filter.address.toLowerCase());
}

和渲染将像

return (
<ul>
{ 
data.filter(filterFunc).map({id, name, address} => (
<li key={id}>{`${name} - ${address}`}</li> 
))
}
</ul>
) 

我使用了这个方法

import React, { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import swal from 'sweetalert';
import axios from 'axios';

const Users = () => {
const navigate = useNavigate();
const [users, setUsers] = useState([]);
const [mainUsers, setMainUsers] = useState([]);
useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/users').then(res => {
setUsers(res.data);
setMainUsers(res.data);
}).catch(err => {
console.log(err);
})
}, []);

const handleSearch = (e) => {
setUsers(mainUsers.filter(u => u.name.toLowerCase()
.includes(e.target.value.toLowerCase())
));
console.log(e.target.value);
}
return (
<div className={`mt-5 p-4 container-fluid`}>
<div className='row my-2 mb-4 justify-content-between w-100 mx-0'>
<div className='form-group col-10 col-md-6 col-lg-4'>
<input type="text" className='form-control shadow' 
placeholder='Search' onChange={handleSearch} />
</div> 
</div>
{users.length ? (
<table className='table'>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">User Name</th>
<th scope="col">Email</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{users.map(u =>
<tr key={u.id}>
<th scope="row">{u.id}</th>
<td>{u.name}</td>
<td>{u.username}</td>
<td>{u.email}</td>
<td>

<i className='fa fa-edit text-warning'></i>

<i className='fa fa-edit text-warning pointer'></i>
</td>
</tr>
)}
</tbody>
</table>
) : (
<h6 className='text-center text-info'>wating ...</h6>
)}
</div>
)
}
export default Users;

最新更新