react-admin: v4 beta1 (upgrading old code): Login form (taken from DEMO) shows "The form is not valid" on submit, while it is valid and does login

What you were expecting:

Login form to not show “not valid” error, when everything is valid.

What happened instead:

It shows “not valid”, while signing in (and eventually does sign in, no problem exists with the form).

image

Steps to reproduce:

I just used the <Login.tsx /> form from DEMO, nothing fancy or changed too much (see code below).

The fields are pre-populated by Chrome (this may be important?). Still, even if I add 1 character and then remove it (just to “touch” the fields), I get the same error message on submit.

Related code:

import * as React from 'react';
import { useState } from 'react';
import PropTypes from 'prop-types';
import { useLocation } from 'react-router-dom';

import {
    Avatar,
    Button,
    Card,
    CardActions,
    CircularProgress,
} from '@mui/material';
import LockIcon from '@mui/icons-material/Lock';
import {
    Form,
    Notification,
    required,
    TextInput,
    useTranslate,
    useLogin,
    useNotify,
} from 'react-admin';

import Box from '@mui/material/Box';

const Login = () => {
    const [loading, setLoading] = useState(false);
    const translate = useTranslate();

    const notify = useNotify();
    const login = useLogin();
    const location = useLocation();

    const handleSubmit = (auth: FormValues) => {
        setLoading(true);
        login(
            auth,
            location.state ? (location.state as any).nextPathname : '/'
        ).catch((error: Error) => {
            setLoading(false);
            notify(
                typeof error === 'string'
                    ? error
                    : typeof error === 'undefined' || !error.message
                    ? 'ra.auth.sign_in_error'
                    : error.message,
                {
                    type: 'warning',
                    messageArgs: {
                        _:
                            typeof error === 'string'
                                ? error
                                : error && error.message
                                ? error.message
                                : undefined,
                    },
                }
            );
        });
    };

    return (
        <Form
            onSubmit={handleSubmit}
            render={({ handleSubmit }) => (
                <form onSubmit={handleSubmit} noValidate>
                    <Box
                        sx={{
                            display: 'flex',
                            flexDirection: 'column',
                            minHeight: '100vh',
                            alignItems: 'center',
                            justifyContent: 'flex-start',
                            background:
                                'url(https://source.unsplash.com/random/1600x900)',
                            backgroundRepeat: 'no-repeat',
                            backgroundSize: 'cover',
                        }}
                    >
                        <Card sx={{ minWidth: 300, marginTop: '6em' }}>
                            <Box
                                sx={{
                                    margin: '1em',
                                    display: 'flex',
                                    justifyContent: 'center',
                                }}
                            >
                                <Avatar sx={{ bgcolor: 'secondary.main' }}>
                                    <LockIcon />
                                </Avatar>
                            </Box>
                            <Box sx={{ padding: '0 1em 1em 1em' }}>
                                <Box sx={{ marginTop: '1em' }}>
                                    <TextInput
                                        autoFocus
                                        source="username"
                                        label={translate('ra.auth.username')}
                                        disabled={loading}
                                        validate={required()}
                                        fullWidth
                                    />
                                </Box>
                                <Box sx={{ marginTop: '1em' }}>
                                    <TextInput
                                        source="password"
                                        label={translate('ra.auth.password')}
                                        type="password"
                                        disabled={loading}
                                        validate={required()}
                                        fullWidth
                                    />
                                </Box>
                            </Box>
                            <CardActions sx={{ padding: '0 1em 1em 1em' }}>
                                <Button
                                    variant="contained"
                                    type="submit"
                                    color="primary"
                                    disabled={loading}
                                    fullWidth
                                >
                                    {loading && (
                                        <CircularProgress
                                            size={25}
                                            thickness={2}
                                        />
                                    )}
                                    {translate('ra.auth.sign_in')}
                                </Button>
                            </CardActions>
                        </Card>
                        <Notification />
                    </Box>
                </form>
            )}
        />
    );
};

Login.propTypes = {
    authProvider: PropTypes.func,
    previousRoute: PropTypes.string,
};

export default Login;

interface FormValues {
    username?: string;
    password?: string;
}

Environment

React-admin version: “react-admin”: “^4.0.0-beta.1” Last version that did not exhibit the issue (if applicable): React version: “react”: “^17.0.2” Browser: Stack trace (in case of a JS error):

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 16 (12 by maintainers)

Most upvoted comments

I’ve narrowed down where notification is coming from.

When validate={required()} is attached for a field, FormContent.tsx file raises this notification from the following lines:

  useEffect(() => {
      if (isInvalid) {
          notify('ra.message.invalid_form', { type: 'warning' });
      }
  }, [isInvalid, notify]);

isInvalid is set by useIsFormInvalid

Right before notification is raised, useIsFormInvalid contains the following values

    const [isInvalid, setIsInvalid] = useState(false); // isInvalid=true
    const { isValid, submitCount } = useFormState(); // isValid=false, submitCount=1
    const submitCountRef = useRef(submitCount); // submitCountRef.current=1