多个 React 管理员列表,在一个屏幕上带有过滤器



我们已经构建了一个基于 React Admin 的管理 UI,为了方便起见,有几次我们希望在单个屏幕上使用多个列表。 例如,在用户详细信息视图中,我们希望显示用户存档的多个地址以及用户进行的购买。用户、地址和购买都是 RA 术语中的"资源"。

它大致看起来像这样:

/* file <...>/resources/users/UserShow.js */
import AddressList from '../addresses/AddressList';
import PurchaseList from '../purchases/PurchaseList';
const UserShow = ({ id, classes, translate, ...props }) => (
<Fragment>
<Show id={id} {...props}>
...render user details here...
</Show>
<AddressList {...props} basePath={'/addresses'} resource={'addresses'} filter={{ userId: id }} />
<PurchaseList {...props} basePath={'/purchases'} resource={'purchases'} filter={{ userId: id }} />
</Fragment>
);

其中大部分似乎工作得很好,但过滤器让我们有些头疼。它周围的一切似乎一次只为一个过滤器构建,没有任何自定义方法(例如,指定一个属性用于 redux 和 react-router 存储中的过滤器,而不是使用硬编码的属性(

有没有人在同一屏幕上制作过两个可过滤的列表并有更多的指针?

我最终想出了一个我想分享的解决方法。

问题在于 RA 将过滤器/页面/排序值传播到查询中,并且它维护过滤器对象的"签名"(相应 JSON 的字符串表示形式(,以便在 URL 更改时检测当前过滤器中的更改。使用此方法,当用户来回导航时,筛选器和分页值将保持活动状态,并且仅在实际字段值更改时更新。

如果每个屏幕有一个列表,这是一件好事,但在我们的例子中,一个列表的过滤器更新会导致值反向传播到屏幕上的所有其他列表中。

首先,我尝试通过修改查询来保留所有筛选器,以便每个筛选器都使用其资源名称作为键。不幸的是,这导致了大量的更改,包括由于修改 RA 内部而复制整个 RA 组件。

注意:RA 已经在其 Redux 存储中保留了每个资源的过滤器值,所以我无法理解为什么他们不使用类似的语法/方法来查询。

另一种选择是完全切断查询的传播。权衡是您无法为特定搜索添加书签,并且在导航时需要重新激活过滤器,但这似乎是一个可以接受的小缺点。

以下是 RA 3 中更新查询的相关代码:https://github.com/marmelab/react-admin/blob/master/packages/ra-core/src/controller/useListParams.ts#L164

history.push({
search: `?${stringify({
...newParams,
filter: JSON.stringify(newParams.filter),
displayedFilters: JSON.stringify(newParams.displayedFilters),
})}`,
});

无法直接修改此行为,但我们可以将自己的历史记录实现提供给 RA 并覆盖搜索参数。相应的猴子补丁如下所示:

const history = createBrowserHistory({
basename: process.env.PUBLIC_URL
});
const oldPush = history.push;
history.push = state => {
oldPush({
...state,
search: null,
});
};

然后可以像这样使用它:

const App = () => (
<Admin
history={history}
...
>
...
</Admin>
);

相关内容

最新更新