根据 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;
};