首页 > 解决方案 > 我可以在 ReactAdmin 应用栏中显示过滤器设置吗?

问题描述

是否可以在 ReactAdmin 应用栏中显示我当前过滤器的元素?

例如,我有一个团队过滤器,以便显示公司中给定团队的销售结果。这一点都在工作。过滤器最终在路由中作为团队 ID,而不是名称。我不确定是否有可能改变这一点,而且我可能也不想这样做;但同样,我想从应用栏中的过滤器中显示选定的团队名称

我已经设置了一个自定义应用栏,但我需要的信息似乎无法作为应用栏的道具。

我可以在 Redux Tools 中看到按 id 的团队已被预加载,位于admin\resources; 但我不确定这些预加载项的布局是否得到官方支持?也没有关于何时加载它们的官方时间?(These must be there because they were loaded for the filter, so logically I guess(??) that the one I need must be there when a filter value has been selected....)

然后,据我所知,要获得当前的过滤器设置,我还必须从router状态部分中提取内容。

我可以尝试将我的自定义应用栏连接到 Redux 并提取上述项目。我想我可以让这个工作 - 但它有强烈的代码气味。'会随着任何 ReactAdmin 更新而中断'的味道,可能与'在错误的时间从错误的地方访问状态'的味道混合在一起!

有没有更清洁、更正式的方式来解决这个问题?

标签: react-admin

解决方案


我已经实施了我在自己的问题中建议的“不受官方支持”的方法。它工作正常,但是 - 公平警告 - 据我所知,它可能会在更新 ReactAdmin 后停止工作。

如果我制定出更官方支持的方法,或者我设法将任何内容提交回 ReactAdmin 项目,我将更新此答案。

所以,这是一个自定义布局:

// CustomLayout.js
import React from 'react';
import { connect } from 'react-redux';
import { Layout, AppBar } from 'react-admin';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import getFilterValue from './getFilterValue';

const useStyles = makeStyles(
  theme => ({
    title: {
      flex: 1,
      textOverflow: 'ellipsis',
      whiteSpace: 'nowrap',
      overflow: 'hidden',
    },
  }),
  { name: 'RaAppBar' }
);

const CustomAppBarUnconnected = (props) => {
  const classes = useStyles(props);
  const { title } = props;
  return (
    <AppBar
      {...props}
    >
      <Typography
        variant="h6"
        color="inherit"
        className={classes.title}
      >
        { title }
      </Typography>
    </AppBar>
  );
}

const mapStateToProps = (state, props) => {
  let team = getFilterValue(state, 'teamId', 'teams'); //, 'name');
  let previousMonth = getFilterValue(state, 'previousMonth');
  let title = `${team ? team.name : 'Company'} Sales. ${previousMonth ? `Previous month = ${previousMonth}` : 'Nothing to see here'}.`;
  return {
    ...props,
    title
  };
};

const CustomAppBar = connect(
  mapStateToProps,
)(CustomAppBarUnconnected);

export const CustomLayout = (props) =>
  <Layout
    {...props}
    appBar={ CustomAppBar }
  />;

使用 .在你的 ReactAdmin 应用程序中应用它<Admin layout={CustomLayout}>。这是一些示例输出:

在此处输入图像描述

大多数自定义布局只是获得看起来像默认应用栏的自定义应用栏所需的样板:它将子级传递给标准 AppBar,应用所需的格式以使标题看起来像标准标题。

如果您希望默认标题与您的自定义标题一起出现,请添加<span id="react-admin-title" />您希望它出现的位置(大概是 旁边的某处{ title })。

如果您还想更彻底地重新安排应用栏(按照ReactAdmin 文档),您需要从头开始创建一个新的自定义 AppBar 类,从原始 ReactAdmin AppBar 类开始。然后就像我在上面所做的那样将它链接到 Redux。

这个自定义布局的关键变化是 AppBar 现在连接到 Redux,这意味着mapStateToProps我们可以调用新函数getFilterValue

// getFilterValue.js
const getFilterValue = (state, source, resource, field) => {
  let value = undefined;

  if (!state || !source) return value;
  
  const filterJSON =
    state.router &&
    state.router.location &&
    state.router.location.query &&
    state.router.location.query.filter;

  if (filterJSON) {
    let filter = JSON.parse(decodeURIComponent(filterJSON));

    let id = filter && filter[source];

    if (id !== undefined) {
      if (!resource) {
        value = id;
      } else {
        const data =
          state.admin &&
          state.admin.resources &&
          state.admin.resources[resource] &&
          state.admin.resources[resource].data;

        if (data) {
          value = data[id];
          if (field) {
            value = value[field];
          }
        }
      }
    }
  }

  return value;
};

export default getFilterValue;

根据您传递给的参数getFilterValue,您可以:

  • 从过滤器中获取原始项目:(state, source)
  • 将过滤器中的原始项目 id 映射到已从 API 获取的对象:(state, source, resource)
  • 将过滤器中的 id 映射到一个项目,然后从该项目中提取一个命名字段:(state, source, resource, field)

undefined如果所需的值不存在,则始终返回;例如,如果您不在带有请求过滤器的页面上,或者如果用户尚未应用过滤器,或者您在任何参数中输入了错字。


推荐阅读