0

I have problem with <ReferenceField>.

On my <List> page, I have rows with UserId and ToolId that I need reference.
I want to show user name and tool code.

But these two columns get stuck in loading state, even though the dataProvider, GET_MANY request succeeded for users and tools.

When I console.log(data), it the data is all there but somehow it's not rendered into <ReferenceField>. And It no error is logged at all.

Any idea what am I doing wrong? Or what's happening?

ReferenceFields still loading

EDIT: I have updated react-admin and now its not displaying loading bar, but just display nothing.

Here is code of List:

export const B_toolList = props => (
    <List {...props}>
        <Datagrid rowClick="edit">
            <TextField source="id" />
            <NumberField source="active" />
            <NumberField source="time" />
            <DateField source="createdAt" />
            <DateField source="updatedAt" />
            <ReferenceField source="UserId" reference="Users">
                <TextField source="name" />
            </ReferenceField>
            <ReferenceField source="ToolId" reference="Tools">
                <TextField source="code" />
            </ReferenceField>            
        </Datagrid>
    </List>
);

I also find out that if i try to inspect ReferenceField element with react-dev-tool, There are no values but just "Loading..." note. But I dont know why... It looks to me that API response is OK.

API res: Btools fetch:

(2) [{…}, {…}]
0:
ToolId: 1
UserId: 1
active: 1
createdAt: "2020-04-08T16:00:03.000Z"
id: 1
time: 1
updatedAt: "2020-04-08T16:00:03.000Z"
__proto__: Object

1:
ToolId: 1
UserId: 2
active: 1
createdAt: "2020-04-08T16:00:03.000Z"
id: 2
time: 1
updatedAt: "2020-04-08T16:00:03.000Z"
__proto__: Object
length: 2
__proto__: Array(0)

Than Users and Tools fetch:

(2) [{…}, {…}]
0: {id: 1, name: "Tomáš Princ", email: "p***@seznam.cz", createdAt: "2020-04-08T15:59:54.000Z", updatedAt: "2020-04-08T15:59:54.000Z"}

1: {id: 2, name: "jhfgjhfg", email: "admin@admin.cz", createdAt: "2020-04-08T18:44:16.000Z", updatedAt: "2020-04-08T18:44:16.000Z"}
length: 2
__proto__: Array(0)
[{…}]
0: {id: 1, code: "guhf", name: "jhfh", state: "ghf", free: 1, …}
length: 1
__proto__: Array(0)

I log this json data in DataProvider and return it like data: json

switch (type) {
            case GET_LIST:
            case GET_MANY:
            case GET_MANY_REFERENCE:
                console.log(json)
                console.log(type)
                if (!headers.has('content-range')) {
                    throw new Error(
                        'The Content-Range header is missing in the HTTP Response. The simple REST 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 Content-Range in the Access-Control-Expose-Headers header?'
                    );
                }
                console.log((headers.get('content-range')))
                return {

                    data: json,
                    total: 
                    //json.length, 
                    parseInt(
                        headers
                            .get('content-range')
                            .split('/')
                            .pop(),
                        10
                    ),
                };

So it look like app have all data it needs, but for some reason still loading and waiting for something.

EDIT 2: I tried little workaround by creating custom element, that load userId and toolId and fetches classic query get user/tool by ID for every row. It works.

const ToolCode = ({ record = {} }) => {

    const dataProvider = useDataProvider();
    const [tool, setTool] = useState();
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState();
    useEffect(() => {
        dataProvider.getOne('tools', { id: record.ToolId })
            .then(({ data }) => {
                setTool(data);
                setLoading(false);
            })
            .catch(error => {
                setError(error);
                setLoading(false);
            })
    }, []);

    if (loading) return <Loading />;
    if (error) return <Error />;
    if (!tool) return null;
    console.log("fetch tools")
    return (
        tool.code
    )
};

const UserName = ({ record = {} }) => {
    const dataProvider = useDataProvider();
    const [user, setUser] = useState();
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState();
    useEffect(() => {
        dataProvider.getOne('users', { id: record.UserId })
            .then(({ data }) => {
                setUser(data);
                setLoading(false);
            })
            .catch(error => {
                setError(error);
                setLoading(false);
            })
    }, []);

    if (loading) return <Loading />;
    if (error) return <Error />;
    if (!user) return null;

    return (
        user.name
    )
};




const B_toolFilter = (props) => (
    <Filter {...props}>
        <TextInput label="Search" source="q" alwaysOn />
        <TextInput label="Title" source="title" defaultValue="Hello, World!" />
    </Filter>
);


export const B_toolList = props => (
    <List {...props}>
        <Datagrid rowClick="edit">
            <TextField source="id" />
            <NumberField source="active" />
            <NumberField source="time" />
            <DateField source="createdAt" />
            <DateField source="updatedAt" />
            <UserName source="UserId" />
            <ToolCode source="ToolId" />            
        </Datagrid>
    </List>
);

Now I can get tool code and user name by IDs form B_Tools, but its much less efficient than GET_MANY method used by ReferenceField..

  • Strange indeed! Kindly add the `code snippets` showing how you have implemented that ``. Would be helpful for us to debug this. Thanks. – MwamiTovi Apr 12 '20 at 10:06
  • App on github here: https://github.com/bobo721/react-admin – Tomáš Princ Apr 12 '20 at 20:59
  • Thanks, I will possibly give a link to a `gist` after trying to debug the same on my machine. What do you mean that the workaround is less efficient? Is it slower to load data? – MwamiTovi Apr 15 '20 at 15:25
  • Hi, well I guess that standard use of ReferenceField works the way, that the list of all items is load (lets say 20 rows), than it looks to ReferenceField source. If there are 10 rows that need reference to UserId 1 and 10 rows that need reference to UserId 2, app just use GetMany method over users table with filter ID IN 1,2 and than fill the ReferenceFields for all rows jus with this one fetch. Workaround just fetch GetOne for every row of the list.. even if its 10 times same user ID. – Tomáš Princ Apr 17 '20 at 06:47

1 Answers1

0

Nwm. Whole time it was just about capital letters of Tools and Users in

     <ReferenceField source="UserId" reference="Users">

and

     <ReferenceField source="ToolId" reference="Tools">

I changes it to

     <ReferenceField source="UserId" reference="users">

and

     <ReferenceField source="ToolId" reference="tools">

Now it works! I just still dont get why it fetched right resources... It is like it is not capital sensitive when it fetches data, but it is capital sensitive when it renders. I dont know. Anyway, I would expect some kind of error message with mistake like this... not just right response and empty render.