首页 > 解决方案 > React Admin 中默认排序、分页参数名称和逻辑不一致

问题描述

我有一个简单的前端 react-admin 应用程序,带有 Flask API,我正在尝试在我的 API 中实现排序、过滤和分页。

我正在使用数据提供者 ra-data-json-server,根据这个规范,我必须使用“_sort”、“_start”和“_end”参数(带有下划线)来实现它。

但是,当我查看我的 Front 应用程序执行的 GET 查询时,排序和分页将类似于:

https://balbla.com/#/users?filter=%7B%7D&order=ASC&page=1&perPage=10&sort=roles

这与那里的文档一致https://marmelab.com/react-admin/DataProviders.html

所以我很困扰,因为:

我错过了什么还是确实存在不一致之处?执行哪一个?对我来说,最简单的方法是让我的后端适应实际的 Front 查询格式,但这不是文档。

谢谢

标签: react-admin

解决方案


一开始我也和你有同样的困惑,然后我遇到了 ra-data-json-server 的源代码。它实现了 _sort、_order、_start 和 _end。首先,您需要在 API 中实现排序和分页。我会建议你在下面使用这个 ra-data-json-server 数据提供者:

import { stringify } from "query-string";
import { fetchUtils } from "ra-core";
/**
 * Maps react-admin que`enter code here`ries to a json-server powered REST API
 *
 * @see https://github.com/typicode/json-server
 *
 * @example
 *
 * getList          => GET http://my.api.url/posts?_sort=title&_order=ASC&_start=0&_end=24
 * getOne           => GET http://my.api.url/posts/123
 * getManyReference => GET http://my.api.url/posts?author_id=345
 * getMany          => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * create           => POST http://my.api.url/posts/123
 * update           => PUT http://my.api.url/posts/123
 * updateMany       => PUT http://my.api.url/posts/123, PUT http://my.api.url/posts/456, PUT http://my.api.url/posts/789
 * delete           => DELETE http://my.api.url/posts/123
 *
 * @example
 *
 * import React from 'react';
 * import { Admin, Resource } from 'react-admin';
 * import jsonServerProvider from 'ra-data-json-server';
 *
 * import { PostList } from './posts';
 *
 * const App = () => (
 *     <Admin dataProvider={jsonServerProvider('http://jsonplaceholder.typicode.com')}>
 *         <Resource name="posts" list={PostList} />
 *     </Admin>
 * );
 *
 * export default App;
 */
var __assign =
  (this && this.__assign) ||
  function () {
    __assign =
      Object.assign ||
      function (t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
          s = arguments[i];
          for (var p in s)
            if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
      };
    return __assign.apply(this, arguments);
  };

export default (function (apiUrl, httpClient) {
  if (httpClient === void 0) {
    httpClient = fetchUtils.fetchJson;
  }
  return {
    getList: function (resource, params) {
      var _a = params.pagination,
        page = _a.page,
        perPage = _a.perPage;
      var _b = params.sort,
        field = _b.field,
        order = _b.order;
      var query = __assign(
        __assign({}, fetchUtils.flattenObject(params.filter)),
        {
          _sort: field,
          _order: order,
          _start: (page - 1) * perPage + 1,
          _end: page * perPage,
        }
      );
      var url = apiUrl + "/" + resource + "?" + stringify(query);
      return httpClient(url).then(function (_a) {
        var headers = _a.headers,
          json = _a.json;
        if (!headers.has("x-total-count")) {
          throw new Error(
            "The X-Total-Count header is missing in the HTTP Response. The jsonServer Data Provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?"
          );
        }
        return {
          data: json,
          total: parseInt(headers.get("x-total-count").split("/").pop(), 10),
        };
      });
    },
    getOne: function (resource, params) {
      return httpClient(apiUrl + "/" + resource + "/" + params.id).then(
        function (_a) {
          var json = _a.json;
          return {
            data: json,
          };
        }
      );
    },
    getMany: function (resource, params) {
      var query = {
        id: params.ids,
      };
      var url = apiUrl + "/" + resource + "?" + stringify(query);
      return httpClient(url).then(function (_a) {
        var json = _a.json;
        return { data: json };
      });
    },
    getManyReference: function (resource, params) {
      var _a;
      var _b = params.pagination,
        page = _b.page,
        perPage = _b.perPage;
      var _c = params.sort,
        field = _c.field,
        order = _c.order;
      var query = __assign(
        __assign({}, fetchUtils.flattenObject(params.filter)),
        ((_a = {}),
        (_a[params.target] = params.id),
        (_a._sort = field),
        (_a._order = order),
        (_a._start = (page - 1) * perPage),
        (_a._end = page * perPage),
        _a)
      );
      var url = apiUrl + "/" + resource + "?" + stringify(query);
      return httpClient(url).then(function (_a) {
        var headers = _a.headers,
          json = _a.json;
        if (!headers.has("x-total-count")) {
          throw new Error(
            "The X-Total-Count header is missing in the HTTP Response. The jsonServer Data Provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?"
          );
        }
        return {
          data: json,
          total: parseInt(headers.get("x-total-count").split("/").pop(), 10),
        };
      });
    },
    update: function (resource, params) {
      return httpClient(apiUrl + "/" + resource + "/" + params.id, {
        method: "PUT",
        body: JSON.stringify(params.data),
      }).then(function (_a) {
        var json = _a.json;
        return { data: json };
      });
    },
    // json-server doesn't handle filters on UPDATE route, so we fallback to calling UPDATE n times instead
    updateMany: function (resource, params) {
      return Promise.all(
        params.ids.map(function (id) {
          return httpClient(apiUrl + "/" + resource + "/" + id, {
            method: "PUT",
            body: JSON.stringify(params.data),
          });
        })
      ).then(function (responses) {
        return {
          data: responses.map(function (_a) {
            var json = _a.json;
            return json.id;
          }),
        };
      });
    },
    create: function (resource, params) {
      return httpClient(apiUrl + "/" + resource, {
        method: "POST",
        body: JSON.stringify(params.data),
      }).then(function (_a) {
        var json = _a.json;
        return {
          data: __assign(__assign({}, params.data), { id: json.id }),
        };
      });
    },
    delete: function (resource, params) {
      return httpClient(apiUrl + "/" + resource + "/" + params.id, {
        method: "DELETE",
      }).then(function (_a) {
        var json = _a.json;
        return { data: json };
      });
    },
    // json-server doesn't handle filters on DELETE route, so we fallback to calling DELETE n times instead
    deleteMany: function (resource, params) {
      return Promise.all(
        params.ids.map(function (id) {
          return httpClient(apiUrl + "/" + resource + "/" + id, {
            method: "DELETE",
          });
        })
      ).then(function (responses) {
        return {
          data: responses.map(function (_a) {
            var json = _a.json;
            return json.id;
          }),
        };
      });
    },
  };
});

推荐阅读