我正在尝试在react-admin项目中使用多个dataprovider,但是出现错误:
Warning: Missing translation for key: "dataProvider is not a function"
function.console。(匿名函数)@ index.js:1452
我的App.js
是这样的:
import React from 'react';
import { render } from 'react-dom';
import { Admin, Resource } from 'react-admin';
import dataProviders from './service/dataproviders';
import UserList1, from './users1';
import UserList2, from './users2';
const App = () => (
render(
<Admin dataProvider={dataProviders}>
<Resource name="users1" list={UserList1} />
<Resource name="users2" list={UserList2} />
</Admin>,
document.getElementById('root'),
)
);
export default App;
我有dataproviders.js
文件:
import simpleRestProvider from 'ra-data-simple-rest';
const dataProviders = [
{ dataProvider: simpleRestProvider('http://path.to.foo.api1'), resources: ['users1'] },
{ dataProvider: simpleRestProvider('http://path.to.foo.api2'), resources: ['users2'] },
];
export default (type, resource, params) => {
const dataProvider = dataProviders.find(dp => dp.resources.includes(resource));
return dataProvider(type, resource, params);
};
这是正确的方法吗?
我检查了此帖子:
Is it possible to have multiple dataProviders in react-admin?
答案 0 :(得分:4)
如果您想知道如何拥有多个数据源以及多个dataProvider类型(即休息),请选择GraphQLe.t.c。 v3 docs状态:
在react-admin v2中,数据提供程序曾经是函数,而不是对象。 React-admin v3可以检测到遗留的数据提供程序并在其周围包装一个对象。因此,为react-admin v2开发的数据提供程序仍可与react-admin v3一起使用。
这意味着<Admin>
组件上的dataProvider属性可以采用:
这意味着,如果您提供的DataProvider是一个函数,则必须创建一个适配器并手动在提供程序上调用这些函数。这是一个例子。
./ dataProviders.js
import { gqlDataProvider, restGQLDataProvider, restProvider } from './buildDataProviders';
// The first assumption is that all resources are unique, thus we can use an object or a map instead of an array. Key = resource, value = DataProvider.
const dataProviders = new Map([
['users', restGQLDataProvider],
['users-local', restProvider],
['Invoice', gqlDataProvider],
['Debtor', gqlDataProvider],
['Status', gqlDataProvider]
]);
export default async (type, resource, params) => {
// Get the DataProvider from the map.
const dataProvider = await dataProviders.get(resource);
// The DataProvider object is wrapped in a function so we can pass in the parameters to get the result.
if (dataProvider instanceof Function) {
return dataProvider(type, resource, params);
}
};
./ buildDataProvider.js
import { gql } from 'apollo-boost';
import buildGraphQLProvider from 'ra-data-graphql-simple';
import { gqlClient, restClient } from './apolloClients';
import simpleRestProvider from 'ra-data-simple-rest';
const LOCAL_REST_ENDPOINT = 'http://localhost:3001/api';
export RestProvider = simpleRestProvider(LOCAL_REST_ENDPOINT);
export const gqlDataProvider = buildGraphQLProvider({
client: gqlClient
});
// This is just an example of the getList provider, you'll have to write the rest.
export const restProvider = (type, resource, params) => {
const providerMap = new Map([
['GET_LIST', async () => {
return await RestProvider.getList(resource, params);
}]
])
export const restGQLDataProvider = (type, resource, params) => {
const providerMap = new Map([
['GET_LIST', async () => {
const query = gql`
query ${resource} {
${resource} @rest(type: "${resource}", path: "/${resource}") {
id
name
username
email
address
phone
website
company
}
}
`;
const result = await restClient.query({ query });
return { data: result.data[resource], total: result.data[resource].length };
}]
])
}
./ apolloClients.js
import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost';
import { RestLink } from 'apollo-link-rest';
import auth from '../../auth';
const GRAPHQL_ENDPOINT = 'http://localhost:4000';
const REST_ENDPOINT = 'http://jsonplaceholder.typicode.com';
const httpLink = new HttpLink({ uri: GRAPHQL_ENDPOINT });
const authLink = new ApolloLink((operation, forward) => {
operation.setContext({
headers: {
'x-api-key': auth.aws_appsync_apiKey
}
});
return forward(operation);
});
export const restClient = new ApolloClient({
link: new RestLink({ uri: REST_ENDPOINT }),
cache: new InMemoryCache()
});
export const gqlClient = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
答案 1 :(得分:3)
您不是在调用找到的dataProvider
,而是从数组调用映射对象。您可以这样修复它:
import simpleRestProvider from 'ra-data-simple-rest';
const dataProviders = [
{ dataProvider: simpleRestProvider('http://path.to.foo.api1'), resources: ['users1'] },
{ dataProvider: simpleRestProvider('http://path.to.foo.api2'), resources: ['users2'] },
];
export default (type, resource, params) => {
const dataProviderMapping = dataProviders.find(dp => dp.resources.includes(resource));
return dataProviderMapping.dataProvider(type, resource, params);
};
答案 2 :(得分:1)
在新版本3.1中我也遇到了同样的问题
我决定建立一个通用的dataProvider
dataProvider.js
import {fetchUtils} from 'ra-core';
import ApiEndpoints from '../config/ApiEndpoints';
import {
restGetList,
restGetOne,
restGetMany,
restGetManyReference,
restUpdate,
restUpdateMany,
restCreate,
restDelete,
restDeleteMany,
} from './rest/index';
import {CONSTANTS} from '../constants';
const httpClientTui = (url, options = {}) => {
if (!options.headers) {
// eslint-disable-next-line no-param-reassign
options.headers = new Headers({Accept: 'application/json'});
}
const token = localStorage.getItem(CONSTANTS.CMS_KEY.TOKEN);
options.headers.set('Authorization', `Bearer ${token}`);
return fetchUtils.fetchJson(url, options);
};
function selectApiEndpoint(resource = '') {
const result = {};
result.apiEndpoint = 'https://jsonplaceholder.typicode.com'; // default parameters
result.apiType = 'rest';
Object.keys(ApiEndpoints).forEach((key) => {
if (ApiEndpoints[key].url.includes(resource)) {
result.apiEndpoint = key.toString();
result.apiType = ApiEndpoints[key].type.toString();
}
});
return {
...result,
};
}
export default (apiUrl, httpClient = httpClientTui) => ({
getList: (resource, params) => {
const {apiEndpoint, apiType} = selectApiEndpoint(resource);
switch (apiType) {
case 'rest':
return restGetList(apiEndpoint, resource, params, httpClient);
default:
return restGetList(apiEndpoint, resource, params, httpClient);
}
},
getOne: (resource, params) => {
const {apiEndpoint, apiType} = selectApiEndpoint(resource);
switch (apiType) {
case 'rest':
return restGetOne(apiEndpoint, resource, params, httpClient);
default:
return restGetOne(apiEndpoint, resource, params, httpClient);
}
},
...
});
ApiEndpoints.js
module.exports = {
'https://jsonplaceholder.typicode.com': {
type: 'rest',
url: [
'posts',
'comments',
'albums',
'photos',
'todos',
'users',
],
},
};
./ rest / index.js
import {fetchUtils} from 'ra-core';
import {stringify} from 'query-string';
/**
* From ra-data-json-server
* https://github.com/marmelab/react-admin/blob/master/packages/ra-data-json-server/src/index.ts
*/
/**
* Get list
* @param apiEndpoint {string} - domain
* @param resource {string} - URI request
* @param params {object} - params request
* @param httpClient {function}
* @returns {{data: object, total: number}}
*/
export function restGetList(apiEndpoint, resource, params, httpClient) {
const {page, perPage} = params.pagination;
const {field, order} = params.sort;
const query = {
...fetchUtils.flattenObject(params.filter),
_sort: field,
_order: order,
_start: (page - 1) * perPage,
_end: page * perPage,
};
const url = `${apiEndpoint}/${resource}?${stringify(query)}`;
return httpClient(url).then(({headers, json}) => {
if (!headers.has('x-total-count')) {
throw new Error(
'not found x-total-count',
);
}
return {
data: json,
total: parseInt(
headers.get('x-total-count').split('/').pop()
),
};
});
}
/**
* Get one record
* @param apiEndpoint {string} - domain
* @param resource {string} - URI request
* @param params {object} - params request
* @param httpClient {function}
* @returns {{data: object}}
*/
export function restGetOne(apiEndpoint, resource, params, httpClient) {
return httpClient(`${apiEndpoint}/${resource}/${params.id}`).then(({json}) => ({
data: json,
}));
}
...