react-admin icon indicating copy to clipboard operation
react-admin copied to clipboard

useQuery returns error after optimistic save

Open megantaylor opened this issue 3 years ago • 9 comments

What you were expecting:

Fetch data with useQuery from inside Edit/Create components and correctly receive data.

What happened instead:

useQuery returns an error after save: error TypeError: Cannot read properties of undefined (reading 'data').

Steps to reproduce:

I am trying to fetch data with useQuery from inside Edit/Create components. I have redirect={false} on the SaveButton so the form stays visible.

If mutationMode={"undoable"}, useQuery returns an error after save: error TypeError: Cannot read properties of undefined (reading 'data').

Related code:

I tried to reproduce this in the CodeSandbox at https://codesandbox.io/s/github/marmelab/react-admin/tree/master/examples/simple but I keep getting this error when it tries to compile:

ERROR in ./src/polyfills.ts
Module not found: Error: Can't resolve 'proxy-polyfill/proxy.min.js' in '/sandbox/src'
 @ ./src/polyfills.ts 5:0-38
 @ multi (webpack)-dev-server/client?http://127.0.0.1:8080 (webpack)/hot/dev-server.js ./src/polyfills.ts

I have reproduced this behavior in the react-admin demo app (pulled the repo and ran the demo locally) by changing src/reviews/ReviewEditToolbar.tsx like so:

import * as React from 'react';
import { Fragment } from 'react';
import MuiToolbar from '@material-ui/core/Toolbar';
import { makeStyles } from '@material-ui/core/styles';

import { SaveButton, DeleteButton, ToolbarProps } from 'react-admin';
import AcceptButton from './AcceptButton';
import RejectButton from './RejectButton';
import { Review } from '../types';
import { useQuery } from 'ra-core';

const useStyles = makeStyles(theme => ({
    root: {
        backgroundColor: theme.palette.background.paper,
        display: 'flex',
        justifyContent: 'space-between',
    },
}));

const ReviewEditToolbar = (props: ToolbarProps<Review>) => {
    const {
        basePath,
        handleSubmitWithRedirect,
        invalid,
        record,
        resource,
        saving,
    } = props;
    const classes = useStyles();

    const { data, loading, error } = useQuery({
        type: 'getMany',
        resource: 'categories',
        payload: { ids: [0] },
    });

    console.log('loading', loading);
    console.log('data', data);
    console.log('error', error);

    if (!record) return null;
    return (
        <MuiToolbar className={classes.root}>
            {record.status === 'pending' ? (
                <Fragment>
                    <AcceptButton record={record} />
                    <RejectButton record={record} />
                </Fragment>
            ) : (
                <Fragment>
                    <SaveButton
                        handleSubmitWithRedirect={handleSubmitWithRedirect}
                        invalid={invalid}
                        saving={saving}
                        redirect={false}
                        submitOnEnter={true}
                    />
                    <DeleteButton
                        basePath={basePath}
                        record={record}
                        resource={resource}
                    />
                </Fragment>
            )}
        </MuiToolbar>
    );
};

export default ReviewEditToolbar;

megantaylor avatar Nov 05 '21 17:11 megantaylor

Can you elaborate on your usecase? What are you trying to achieve? I tried the code you put in the demo without having any issue. And please, follow the issue template

djhi avatar Nov 09 '21 11:11 djhi

I've updated my issue to follow the issue template.

I tried to reproduce this in the CodeSandbox at https://codesandbox.io/s/github/marmelab/react-admin/tree/master/examples/simple but I keep getting this error when it tries to compile:

ERROR in ./src/polyfills.ts Module not found: Error: Can't resolve 'proxy-polyfill/proxy.min.js' in '/sandbox/src' @ ./src/polyfills.ts 5:0-38 @ multi (webpack)-dev-server/client?http://127.0.0.1:8080 (webpack)/hot/dev-server.js ./src/polyfills.ts

I am able to reproduce the issue by running the demo from the repo locally. The error is visible in the browser devtools console.

megantaylor avatar Nov 09 '21 17:11 megantaylor

also experienced this issue.

  • redirect={false} on a <SimpleForm /> component (rendered by <Edit />)
  • useQuery returns the error

Error happens here on line 134

image

I believe the variable _a is undefined for some reason. However, no network request fails.

Also, the issue only happens after the save. If you refresh the page, either through react-admin's refresh button or browser refresh, useQuery works fine.

jasonlimantoro avatar Nov 18 '21 01:11 jasonlimantoro

I made a codesandbox fork here: https://codesandbox.io/s/keen-snowflake-tmftd

The changes I made are in src/posts/PostEdit.tsx

To reproduce the error:

  1. Click on a Post to go to Post Edit view
  2. Make some change, click save
  3. Wait for save to complete
  4. Look in the console, you will see: error TypeError: Cannot read properties of undefined (reading 'data')

megantaylor avatar Nov 18 '21 19:11 megantaylor

any progress on this issue?

megantaylor avatar Dec 08 '21 22:12 megantaylor

same issue, but i used dataProviderProxy from useDataProvider hook (useQuery works the same, calling useDataProvider too)

usecase: my api entity has multiple relationships and complex formatting logic on userside. I need to fetch some data (in my List or Datagrid component) for processing this in FunctionField. Yeah i know about ReferenceField but it doesn't suit me because api return nested data structures with many-to-many relationships.

another example in codesandbox: https://codesandbox.io/s/usedataprovider-example-jb68p-jb68p step to reproduce same as @megantaylor say

  1. for simplicity list has "fetched value" col and succesfuly show fetched data image

  2. Click on any row for open edit form

  3. Edit text field value and press save button

  4. After redirect we have re-mount list and dataProvider.getList return undefined image

some notes: as already mentioned, the problem lies in the mutationMode: 'optimistic' | 'undoable' if you push REFRESH_VIEW action, data will show as expected image

workaround:

  • instead of useQuery and useDataProvider hooks you can call pure dataProvider object methods const dataProvider = useContext(DataProviderContext); (from docs)
  • specialized hooks (useGetList, useUpdate, etc) works fine too
  • disable optimistic mode by pass prop to Create/Edit components <Edit mutationMode="pessimistic" {...props}>

JustMonk avatar Dec 24 '21 06:12 JustMonk

Reproduced, thanks for the codesandbox.

fzaninotto avatar Dec 24 '21 08:12 fzaninotto

Hi! Just wanted to check in on this. Is it fixed as part of v4? If not, any plan on addressing it soon?

jakedeg avatar Jun 24 '22 20:06 jakedeg

We no longer export a useQuery in v4, so I supposed it's fixed

fzaninotto avatar Jun 27 '22 14:06 fzaninotto