返回
React 通用解决方案——筛选与路由联动,让你的筛选器效果更佳
前端
2024-02-17 15:47:55
背景介绍
在前后端开发不分离的「远古时代」,页面的筛选器操作筛选一般会同步变更URL,触发浏览器刷新,从而正确呈现「选定筛选值」的筛选器和根据筛选器过滤后的列表数据。这种渲染模式的流程大致如下:
- 用户在筛选器上选择一个值。
- 筛选器组件将选定的值发送给父组件。
- 父组件将选定的值存储在状态中。
- 父组件使用选定的值更新URL。
- 浏览器刷新页面。
- 组件重新渲染,并使用新的URL中的选定值来显示筛选器和列表数据。
这种渲染模式虽然简单易懂,但存在一些缺点:
- 页面闪烁: 由于浏览器需要刷新页面,因此在筛选器操作后会看到页面闪烁。
- 丢失状态: 如果用户在筛选器操作后刷新页面,则筛选器状态将丢失。
- URL不直观: URL中包含筛选器值,这使得URL不直观,也不利于搜索引擎优化。
React中的筛选和路由联动
为了解决上述问题,我们可以使用React中的路由和状态管理来实现筛选和路由的联动。
1. 使用路由管理筛选器状态
我们可以使用React Router来管理筛选器状态。当用户在筛选器上选择一个值时,我们可以使用history.push()
方法来更新URL,并将选定的值作为查询参数添加到URL中。例如:
import { useHistory } from "react-router-dom";
const Filter = () => {
const history = useHistory();
const handleFilterChange = (value) => {
history.push({
pathname: "/products",
search: `?filter=${value}`,
});
};
return (
<select onChange={(e) => handleFilterChange(e.target.value)}>
<option value="all">All</option>
<option value="category1">Category 1</option>
<option value="category2">Category 2</option>
</select>
);
};
2. 使用状态管理工具管理筛选器状态
我们也可以使用状态管理工具来管理筛选器状态。例如,我们可以使用Redux来存储筛选器状态。当用户在筛选器上选择一个值时,我们可以使用Redux的dispatch()
方法来更新筛选器状态。例如:
import { useDispatch } from "react-redux";
const Filter = () => {
const dispatch = useDispatch();
const handleFilterChange = (value) => {
dispatch({
type: "SET_FILTER",
payload: value,
});
};
return (
<select onChange={(e) => handleFilterChange(e.target.value)}>
<option value="all">All</option>
<option value="category1">Category 1</option>
<option value="category2">Category 2</option>
</select>
);
};
3. 使用自定义组件管理筛选器状态
如果我们不想使用路由或状态管理工具,我们也可以使用自定义组件来管理筛选器状态。例如,我们可以创建一个Filter
组件来存储筛选器状态。当用户在筛选器上选择一个值时,我们可以使用setState()
方法来更新筛选器状态。例如:
class Filter extends React.Component {
constructor(props) {
super(props);
this.state = {
filter: "all",
};
this.handleFilterChange = this.handleFilterChange.bind(this);
}
handleFilterChange(value) {
this.setState({
filter: value,
});
}
render() {
return (
<select onChange={this.handleFilterChange}>
<option value="all">All</option>
<option value="category1">Category 1</option>
<option value="category2">Category 2</option>
</select>