根据 API 调用将获取的资源添加到已知资源
Adding fetched resources to knownresources based on API call
我正在尝试根据 API 调用添加资源。我可以毫无问题地添加 knownResources,我也可以自己添加 fetchedResources - 但是我不能将两者结合起来。
文档展示了如何根据从 API 查询的权限显示资源,但没有详细说明如何在未声明资源的情况下动态添加资源:
https://marmelab.com/react-admin/Admin.html#declaring-resources-at-runtime
如果两者结合(如下所示),CoreAdminRouter 会抛出错误:
TypeError: child.props 未定义
任何关于如何解决的想法都将受到赞赏!代码如下:
import 'babel-polyfill';
import React from 'react';
import { Admin, Resource } from 'react-admin';
import { restClient } from 'ra-data-feathers';
import { Route } from 'react-router-dom';
import feathersClient from './feathersClient';
import englishMessages from 'ra-language-english';
// import customRoutes from './customRoutes';
import { createBrowserHistory as createHistory } from 'history';
import createRealtimeSaga from "./createRealtimeSaga";
import { Contacts } from './services/contacts';
import { Group, GroupMember } from './services/groups';
import { Albums, Photos, PublicPhotosList } from './services/photos';
import UserIcon from '@material-ui/icons/AccountCircle';
import GroupIcon from '@material-ui/icons/Group';
import GroupIcon from '@material-ui/icons/GroupWork';
import StarIcon from '@material-ui/icons/StarRate';
import FolderSpecialIcon from '@material-ui/icons/FolderSpecial';
const authClientOptions = {
storageKey: 'feathers-jwt',
authenticate: { strategy: 'local' }
};
const history = createHistory();
const options = {
usePatch: false, // Use PATCH instead of PUT for UPDATE requests. Optional.
contacts: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'ContactId' // If this specific table uses an id field other than 'id'. Optional.
},
group: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'GroupId' // If this specific table uses an id field other than 'id'. Optional.
},
groupmember: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'GroupMemberID' // If this specific table uses an id field other than 'id'. Optional.
},
albums: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
photos: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'PhotoId' // If this specific table uses an id field other than 'id'. Optional.
},
"photos/albums/1/": { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
"photos/albums/2/": { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
}
const dataProvider = restClient(feathersClient, options)
const realTimeSaga = createRealtimeSaga(dataProvider);
const messages = {
en: englishMessages,
}
const i18nProvider = locale => messages[locale];
const knownResources = [
<Resource name="contacts" list={ContactsList} show={ContactsShow} icon={UserIcon} />,
<Resource name="group" list={GroupList} show={GroupShow} icon={GroupIcon}/>,
<Resource name="groupmember" list={GroupMemberList} show={GroupMemberShow} icon={GroupIcon}/>,
<Resource name="albums" list={AlbumList} show={AlbumsShow} icon={GroupIcon}/>,
<Resource name="photos" list={PhotoList} show={PhotosShow} icon={GroupIcon}/>,
//******************************************************************
//**These resources need to be dynamically Added based on API Call**
//******************************************************************
// <Resource name="photos/albums/1/" list={PublicPhotosList} icon={StarIcon}/>,
// <Resource name="photos/albums/2/" list={PublicPhotosList} icon={StarIcon}/>,
// <Resource name="photos/albums/3/" list={PublicPhotosList} icon={StarIcon}/>,
// etc.
];
// const fetchResources = permissions =>
// fetch('https://myapi/resources', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify(permissions),
// })
// .then(response => response.json())
// .then(json => knownResources.filter(resource => json.resources.includes(resource.props.name)));
const fetchResources = () =>
fetch('https://jsonplaceholder.typicode.com/albums/hasphotos/true?$limit=10')
.then(function(response){return response.json()})
.catch(error => console.error('Error:', error))
.then(function(schemas){
var filtered = schemas.data
// console.log(schema.data)
return filtered.map((schema, index)=>{
let name = 'photos/album/'+schema.AlbumId
options[name] = {
id: 'AlbumId'
}
var resource;
if(schema.Results.length!==0){
resource = <Resource
name={'photos/albums/'+schema.AlbumId}
list={PublicPhotosList}
options = {{
label:schema.AlbumName
}}/>;
knownResources.push(resource);
console.log(knownResources)
}
return knownResources
})
})
.catch(error => console.error('Error:', error))
const App = () => (
<Admin
// authProvider={authClient(feathersClient, authClientOptions)}
restClient={restClient(feathersClient, options)}
dataProvider={restClient(feathersClient, options)}
customSagas={[realTimeSaga]}
locale="en"
i18nProvider={i18nProvider}
// customRoutes={customRoutes}
history={history}
// theme={theme}
>
//{knownResources}
{fetchResources}
</Admin>
);
export default App;
问题似乎是由 return 语句的放置位置引起的。这有效 - 它获取数据,然后根据 returned 创建资源。
const fetchResources = async ( ) => {
let response = await fetch('https://jsonplaceholder.typicode.com/albums/hasphotos/true?$limit=10');
let schemas = await response.json();
var filtered = schemas.data.filter(a=>a.Results.length);
filtered.map(schema => {
let name = 'photos/album/'+schema.AlbumId
var resource = <Resource
key='AlbumId'
name={'photos/album/'+schema.AlbumId}
list={PublicPhotosList}
options = {{
label:schema.Album
}}
/>;
options[name] = {
id: 'AlbumId'
}
knownResources.push(resource)
return;
}
);
console.log(knownResources)
return knownResources;
};
我正在尝试根据 API 调用添加资源。我可以毫无问题地添加 knownResources,我也可以自己添加 fetchedResources - 但是我不能将两者结合起来。
文档展示了如何根据从 API 查询的权限显示资源,但没有详细说明如何在未声明资源的情况下动态添加资源:
https://marmelab.com/react-admin/Admin.html#declaring-resources-at-runtime
如果两者结合(如下所示),CoreAdminRouter 会抛出错误:
TypeError: child.props 未定义
任何关于如何解决的想法都将受到赞赏!代码如下:
import 'babel-polyfill';
import React from 'react';
import { Admin, Resource } from 'react-admin';
import { restClient } from 'ra-data-feathers';
import { Route } from 'react-router-dom';
import feathersClient from './feathersClient';
import englishMessages from 'ra-language-english';
// import customRoutes from './customRoutes';
import { createBrowserHistory as createHistory } from 'history';
import createRealtimeSaga from "./createRealtimeSaga";
import { Contacts } from './services/contacts';
import { Group, GroupMember } from './services/groups';
import { Albums, Photos, PublicPhotosList } from './services/photos';
import UserIcon from '@material-ui/icons/AccountCircle';
import GroupIcon from '@material-ui/icons/Group';
import GroupIcon from '@material-ui/icons/GroupWork';
import StarIcon from '@material-ui/icons/StarRate';
import FolderSpecialIcon from '@material-ui/icons/FolderSpecial';
const authClientOptions = {
storageKey: 'feathers-jwt',
authenticate: { strategy: 'local' }
};
const history = createHistory();
const options = {
usePatch: false, // Use PATCH instead of PUT for UPDATE requests. Optional.
contacts: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'ContactId' // If this specific table uses an id field other than 'id'. Optional.
},
group: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'GroupId' // If this specific table uses an id field other than 'id'. Optional.
},
groupmember: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'GroupMemberID' // If this specific table uses an id field other than 'id'. Optional.
},
albums: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
photos: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'PhotoId' // If this specific table uses an id field other than 'id'. Optional.
},
"photos/albums/1/": { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
"photos/albums/2/": { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
}
const dataProvider = restClient(feathersClient, options)
const realTimeSaga = createRealtimeSaga(dataProvider);
const messages = {
en: englishMessages,
}
const i18nProvider = locale => messages[locale];
const knownResources = [
<Resource name="contacts" list={ContactsList} show={ContactsShow} icon={UserIcon} />,
<Resource name="group" list={GroupList} show={GroupShow} icon={GroupIcon}/>,
<Resource name="groupmember" list={GroupMemberList} show={GroupMemberShow} icon={GroupIcon}/>,
<Resource name="albums" list={AlbumList} show={AlbumsShow} icon={GroupIcon}/>,
<Resource name="photos" list={PhotoList} show={PhotosShow} icon={GroupIcon}/>,
//******************************************************************
//**These resources need to be dynamically Added based on API Call**
//******************************************************************
// <Resource name="photos/albums/1/" list={PublicPhotosList} icon={StarIcon}/>,
// <Resource name="photos/albums/2/" list={PublicPhotosList} icon={StarIcon}/>,
// <Resource name="photos/albums/3/" list={PublicPhotosList} icon={StarIcon}/>,
// etc.
];
// const fetchResources = permissions =>
// fetch('https://myapi/resources', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify(permissions),
// })
// .then(response => response.json())
// .then(json => knownResources.filter(resource => json.resources.includes(resource.props.name)));
const fetchResources = () =>
fetch('https://jsonplaceholder.typicode.com/albums/hasphotos/true?$limit=10')
.then(function(response){return response.json()})
.catch(error => console.error('Error:', error))
.then(function(schemas){
var filtered = schemas.data
// console.log(schema.data)
return filtered.map((schema, index)=>{
let name = 'photos/album/'+schema.AlbumId
options[name] = {
id: 'AlbumId'
}
var resource;
if(schema.Results.length!==0){
resource = <Resource
name={'photos/albums/'+schema.AlbumId}
list={PublicPhotosList}
options = {{
label:schema.AlbumName
}}/>;
knownResources.push(resource);
console.log(knownResources)
}
return knownResources
})
})
.catch(error => console.error('Error:', error))
const App = () => (
<Admin
// authProvider={authClient(feathersClient, authClientOptions)}
restClient={restClient(feathersClient, options)}
dataProvider={restClient(feathersClient, options)}
customSagas={[realTimeSaga]}
locale="en"
i18nProvider={i18nProvider}
// customRoutes={customRoutes}
history={history}
// theme={theme}
>
//{knownResources}
{fetchResources}
</Admin>
);
export default App;
问题似乎是由 return 语句的放置位置引起的。这有效 - 它获取数据,然后根据 returned 创建资源。
const fetchResources = async ( ) => {
let response = await fetch('https://jsonplaceholder.typicode.com/albums/hasphotos/true?$limit=10');
let schemas = await response.json();
var filtered = schemas.data.filter(a=>a.Results.length);
filtered.map(schema => {
let name = 'photos/album/'+schema.AlbumId
var resource = <Resource
key='AlbumId'
name={'photos/album/'+schema.AlbumId}
list={PublicPhotosList}
options = {{
label:schema.Album
}}
/>;
options[name] = {
id: 'AlbumId'
}
knownResources.push(resource)
return;
}
);
console.log(knownResources)
return knownResources;
};