Using React Hook Form with other component - reactjs

I want to create dynamic form with react-hook-form.
Below is my code.
I want to create a dialog for entering a detailed profile in a separate component and use it in MainForm.
I can display the DetailForm, but the values entered in it are not reflected.
Data on the DetailForm component is not included when submitting.
Any guidance on how to do this would be greatly appreciated.
MainForm
import React from 'react';
import {
useForm,
Controller,
useFieldArray
} from 'react-hook-form';
import {
Button,
TextField,
List,
ListItem,
IconButton,
} from '#material-ui/core';
import DetailForm from '#components/DetailForm'
import AddCircleOutlineIcon from '#material-ui/icons/AddCircleOutline';
function MainForm(props:any) {
const { control, handleSubmit, getValues } = useForm({
mode: 'onBlur',
defaultValues: {
profiles: [
{
firstName: '',
lastName: '',
email: '',
phone: ''
}
]
}
});
const { fields, append, remove } = useFieldArray({
control,
name: 'profiles',
});
const onSubmit = () => {
const data = getValues();
console.log('data: ', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<List>
fields.map((item, index) => {
return (
<ListItem>
<Controller
name={`profiles.${index}.firstName`}
control={control}
render={({field}) =>
<TextField
{ ...field }
label="First Name"
/>
}
/>
<Controller
name={`profiles.${index}.lastName`}
control={control}
render={({field}) =>
<TextField
{ ...field }
label="Last Name"
/>
}
/>
<DetailForm index={index} />
</ListItem>
)
})
</List>
<IconButton onClick={() => append({})}>
<AddCircleOutlineIcon />
</IconButton>
<Button
type='submit'
>
SAVE
</Button>
</form>
)
}
DetailForm
import React from 'react';
import {
Button,
TextField,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '#material-ui/core';
export default function DetailForm(props: any) {
const [dialogState, setDialogState] = React.useState<boolean>(false);
const handleOpen = () => {
setDialogState(true);
};
const handleClose = () => {
setDialogState(false);
};
return (
<>
<Button
onClick={handleOpen}
>
Set Detail Profile
</Button>
<Dialog open={dialogState}>
<DialogTitle>Detail Profile</DialogTitle>
<DialogContent>
<TextField
name={`profiles.${props.index}.email`}
label="Email Address"
/>
<TextField
name={`profiles.${props.index}.phone`}
label="Phone Number"
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>
Cancel
</Button>
<Button onClick={handleClose}>
Add
</Button>
</DialogActions>
</Dialog>
</>
)
}

You have to register those fields inside your <Dialog /> component - just pass control to it. It's also important to set an inline defaultValue when using <Controller /> and useFieldArray. From the docs:
inline defaultValue is required when working with useFieldArray by integrating with the value from fields object.
One other minor thing: You should also pass the complete fieldId to your <Dialog /> component instead of just passing the index. This way it would be easier to change the fieldId in one place instead of editing all fields in your <Dialog /> component.
MainForm
<ListItem key={item.id}>
<Controller
name={`profiles.${index}.firstName`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="First Name" />
)}
/>
<Controller
name={`profiles.${index}.lastName`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="Last Name" />
)}
/>
<DetailForm control={control} fieldId={`profiles.${index}`} />
</ListItem>
DetailForm
export default function DetailForm({ control, fieldId }) {
const [dialogState, setDialogState] = React.useState(false);
const handleOpen = () => {
setDialogState(true);
};
const handleClose = () => {
setDialogState(false);
};
return (
<>
<Button onClick={handleOpen}>Set Detail Profile</Button>
<Dialog open={dialogState}>
<DialogTitle>Detail Profile</DialogTitle>
<DialogContent>
<Controller
name={`${fieldId}.email`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="Email Address" />
)}
/>
<Controller
name={`${fieldId}.phone`}
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="Phone Number" />
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={handleClose}>Add</Button>
</DialogActions>
</Dialog>
</>
);
}

Related

ReactJS Typescript Material UI Dialog Reusable Component

Please assist me. I was creating a Reusable Material UI Modal Dialog component so that I can call it from any component but it is not showing whenever I click the button on any component. See the code below :
*********************THE MODAL COMPONENT
--->ReusableDialog.tsx
import React, { useState, ReactNode } from 'react';
import { createStyles, Theme, withStyles, WithStyles } from '#material-ui/core/styles';
import { Button,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions } from '#mui/material';
import IconButton from '#material-ui/core/IconButton';
import Typography from '#material-ui/core/Typography';
type Props = {
show: boolean,
title: string,
body: ReactNode,
onSubmitButtonClicked: () => void;
closeDialog: () => void;
};
export default function AppModalDialog(Props: Props) {
const [open, setOpen] = useState(Props.show)
return <>
<Dialog
open={Props.show}
onClose = {() => setOpen(false)}
aria-labelledby='dialog-title'
aria-describedby='dialog-description'
>
<DialogTitle id='dialog-title'> {Props.title} </DialogTitle>
<DialogContent>
<DialogContentText id='dialog-description' >{Props.body}</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() =>Props.closeDialog}>Cancel</Button>
<Button autoFocus onClick={() => Props.onSubmitButtonClicked()}>Submit</Button>
</DialogActions>
</Dialog>
</>
}
*************************THE FORM THAT WILL DISPLAY IN THE MODAL
childFormDialog.tsx
interface paymentTypeProps{
paymenttype: string;
}
const baseURL = process.env.REACT_APP_API_BASE_URL_LOCAL;
const childFormDialog = (Props: paymentTypeProps) => {
const navigate = useNavigate();
const [submitting, setSubmitting] = useState("");
const [errormsg, setErrorMsg] = useState("");
const [fullname, setFullName] = useState<string>('');
const [email, setEmail] = useState<string>('');
const [phone, setPhone] = useState<string>('');
const [paymenttypes, setPaymenttypes] = useState(Props.paymenttype)
useLayoutEffect(()=>{
setFullName(secureLocalStorage.getItem('fullname').toString());
setEmail(secureLocalStorage.getItem('email').toString());
setPhone(secureLocalStorage.getItem('phone').toString());
//setPaymentType(Props.)
}, []);
const validationSchema = yup.object({
fullname: yup.string().required('Your full name is needed'),
email: yup.string().required('An email address is needed'),
phone: yup.string().required('Phone number is needed'),
amount: yup.string().required('Please type an amount'),
paymenttitle: yup.string().required('Please indicate title for this payment'),
paymentdescription: yup.string(),
});
const formik = useFormik({
initialValues: {
fullname: fullname,
email: email,
phone: phone,
amount: '',
paymenttitle: '',
paymentdescription: '',
},
validationSchema: validationSchema,
onSubmit: async (values) => {
handleFormSubmit();
}
})
const makePayment = () => {
}
const handleFormSubmit = () => {
var data = {
fullname: formik.values.fullname,
email: formik.values.email,
phone: formik.values.phone,
amount: formik.values.amount,
paymenttitle: formik.values.paymentdescription,
paymentdescription: formik.values.paymentdescription,
}
if(paymenttypes =='A') {
configPaymentAPI_A(data.amount, data.email, data.phone, data.fullname, data.paymenttitle, data.paymentdescription)
}
else{
configPaymentAPI_B(data.email, data.amount)
}
} //function closed
return <>
<form style={{width: '100%}'}}>
<div className="row px-3">
<Grid container direction={"column"} spacing={2}>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Payment Title"
name="paymenttitle"
placeholder="Payment Title"
variant="standard"
type="text"
value={formik.values.paymenttitle}
onChange={formik.handleChange}
error={formik.touched.paymenttitle && Boolean(formik.errors.paymenttitle)}
helperText={formik.touched.paymenttitle && formik.errors.paymenttitle}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CallToActionIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Full Name"
name="fullname"
placeholder="Your Full Name"
variant="standard"
type="text"
aria-readonly
value={formik.values.fullname}
onChange={formik.handleChange}
error={formik.touched.fullname && Boolean(formik.errors.fullname)}
helperText={formik.touched.fullname && formik.errors.fullname}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PersonOutlineIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Email Address"
name="email"
placeholder="Your Email"
variant="standard"
type="email"
aria-readonly
value={formik.values.email}
onChange={formik.handleChange}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<EmailIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Phone Number"
name="phone"
placeholder="Your Phone Number"
variant="standard"
type="number"
aria-readonly
value={formik.values.phone}
onChange={formik.handleChange}
error={formik.touched.phone && Boolean(formik.errors.phone)}
helperText={formik.touched.phone && formik.errors.phone}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PhoneIphoneIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Amount"
name="amount"
placeholder="Amount To Be Paid"
variant="standard"
type="number"
value={formik.values.amount}
onChange={formik.handleChange}
error={formik.touched.amount && Boolean(formik.errors.amount)}
helperText={formik.touched.amount && formik.errors.amount}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CallToActionIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<TextField
style ={{width: '100%'}}
label="Payment Description"
name="paymentdescription"
placeholder="Type some notes for this payment"
variant="standard"
type="text"
value={formik.values.paymentdescription}
onChange={formik.handleChange}
error={formik.touched.paymentdescription && Boolean(formik.errors.paymentdescription)}
helperText={formik.touched.paymentdescription && formik.errors.paymentdescription}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<EventNoteIcon color="primary" />
</InputAdornment>
),
}} />
</Grid>
<Grid item>
<Button
type="submit"
variant="contained"
startIcon={<SendIcon />}
disableRipple
>Remit Your Payment </Button>
</Grid>
</Grid>
</div>
</form>
</>
}
export default childFormDialog
********************THE PARENT FORM THAT CALL/INVOKE THE DIALOG ONCLICK OF A LINK
--->Parent.tsx
const [paymentTypState, setPaymentTypState] = useState<string>('');
const [modalDisplay, setModalDisplay] = useState<boolean>(false);
const [close, setClose] = useState<boolean>(true);
const [open, setOpen] = useState(false);
const onclickPaymentA = () => {
setOpen(true);
setPaymentTypState('A');
}
const onclickPaymentB = () => {
setOpen(true);
setPaymentTypState('B');
}
const handleDialogOnSubmit = () => {
}
return <>
<a onClick={onclickPaymentA}>
<img src="../assets/images/paymentA.png" style={{width:300, height: 150}}/>
</a>
<a onClick={onclickPaymentB}>
<img src="../assets/images/paymentB.png" style={{width:300, height: 150}}/>
</a>
<ReusableDialog
show = { open }
title = 'Top Up Your Wallet'
body = {<childFormDialog paymenttype={paymentTypState} />}
closeDialog = {() => setOpen(false) }
onSubmitButtonClicked = { handleDialogOnSubmit }
/>
</>
**********THE ROUTER OF THE APPLICATION THAT USES BROWSERROUTER
import React from "react";
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Login from './Login';
import Register from './Register';
import Dashboard from './Dashboard';
import Parent from './Parent';
<Route path="/login" element={<Login />}>
</Route>
<Route path="/register" element={<Register />}>
</Route>
<Route path="/dashboard" element={<AuthenticatedRoute element={<Dashboard />} />}>
<Route path="/parent" element={<AuthenticatedRoute element={<Parent />} />}>
I can navigate from other page to Parent.tsx and I can navigate from Parent.tsx to other pages. I don't have childFormDialog that will be displayed in the Material UI Dialog in the router because no page calls the childFormDialog through hyperlink or the menu link. The childFormDialog is called from the Parent.tsx file and it should displays in the Reusable Dialog Component on the same page.
The current behavior of the form when I click on the hyperlink is that it only shows a blank page and remain on the same URL without reloading/refreshing the page. The expected behavior is for the Material UI Dialog to display with the childFormDialog component displays in the Material UI Dialog.
I will appreciate your kind assistance
If you forgot to wrap your app in a BrowserRouter and attempt to instantiate the useNavigate hook, then your childFormDialog component would quietly fail and not render anything.

How can I use useForm's register with dynamic parameter?

I want to create a form by using react-hook-form, but I am having trouble with it. As I found, there was a big change at v7 so the code I used as a reference is not working. I tried to modify it, and I figured out the problem is with the registering, but I cannot pass that name parameter dynamically.
My main component.
import React from 'react';
import i18next from 'i18next';
import { Button, Grid, Typography } from '#material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { Link } from 'react-router-dom';
import FormInput from './CustomTextField'
const AddressForm = ({ next }) => {
const methods = useForm();
return (
<>
<Typography variant="h6" gutterBottom>
{i18next.t('shipping_address')}
</Typography>
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit((data) => {
console.log(data);
next({ ...data })})}>
<Grid container spacing={3}>
<FormInput required register={methods.register} name='lastName' label={i18next.t('last_name')} />
<FormInput required register={methods.register} name='firstName' label={i18next.t('first_name')} />
<FormInput required register={methods.register} name='email' label={i18next.t('mail')} />
<FormInput required register={methods.register} name='zip' label={i18next.t('zip_code')} />
<FormInput required register={methods.register} name='city' label={i18next.t('city')} />
<FormInput required register={methods.register} name='address1' label={i18next.t('address_1')} />
</Grid>
<br />
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Button component={Link} to="/cart" variant="outlined">
{i18next.t('back_to_cart')}
</Button>
<Button type="submit" variant="contained" color="primary">
{i18next.t('next_step')}
</Button>
</div>
</form>
</FormProvider>
</>
)
}
export default AddressForm
CustomTextField component:
import React from 'react';
import { TextField, Grid } from '#material-ui/core';
import { useFormContext, Controller } from 'react-hook-form';
const CustomTextField = ({ name, label, register, required}) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={name}
render = {(field) => (
<TextField
{...register({name})} // <--- It is not working like this
label={label}
required={required}
/>
)}
/>
</Grid>
)
}
export default CustomTextField
By the doc: https://react-hook-form.com/api/useform/register
it takes the input field's name as a parameter, if I pass it in as a string, it works fine. How can I pass the name's value as a parameter to the register() function?
The problem is you're mixing RHF's <Controller /> and register. As Mui's <TextField /> is an external controlled component you should use <Controller />. Check the docs here for more info.
const CustomTextField = ({ name, label, register, required}) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={name}
render={({ field: { ref, ...field } }) => (
<TextField
{...field}
inputRef={ref}
label={label}
required={required}
/>
)}
/>
</Grid>
)
}
If you really want to use register here, you have to remove the wrapping <Controller /> and pass a name as a string instead as an object like you are doing right now. But i would recommend to use <Controller /> as with register you are losing the functionality of setting up the correct ref for your <TextField /> input element as it is linked via the inputRef prop instead of using ref which RHF register uses.
const CustomTextField = ({ name, label, register, required}) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<TextField
{...register(name)}
label={label}
required={required}
/>
</Grid>
)
}

Console Log from Props

I'm confused as I have managed to get my data to be logged via different means, but confused as to why when I use props for the data (rather than repeating code) it will not log the input.
For reference, I have a field component that will take props to drive what my react-hook-form TextField will request. I'd like to expand on the component but until it logs my data, I cannot proceed!
Below is the code that actually logs my data:
import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField, Button } from "#material-ui/core/";
const NewRequest = () => {
const { register, handleSubmit, control } = useForm();
const onSubmit = (data) => console.log(data);
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name='firstName'
render={({ field: { onChange, onBlur, value, name, ref } }) => (
<TextField
label='First Name'
variant='filled'
size='small'
onBlur={onBlur}
onChange={onChange}
checked={value}
inputRef={ref}
/>
)}
/>
<br />
<br />
<Button type='submit' variant='contained'>
Submit
</Button>
</form>
</div>
);
};
export default NewRequest;
I have then moved the Controller, TextField to create a component:
import React from "react";
import { Controller, useForm } from "react-hook-form";
import { TextField } from "#material-ui/core/";
const TextFieldComponent = (props) => {
const { name, label, size, variant } = props;
const { control } = useForm();
return (
<div>
<Controller
control={control}
name={name}
render={({ field: { onChange, onBlur, value, ref } }) => (
<TextField
label={label}
variant={variant}
size={size}
onBlur={onBlur}
onChange={onChange}
checked={value}
inputRef={ref}
/>
)}
/>
</div>
);
};
export default TextFieldComponent;
Which I am using inside of another component (to generate a full form) and passing through my props (I will make a different component for Button, but for now it is where it is):
import React from "react";
import { useForm, Controller } from "react-hook-form";
import TextFieldComponent from "./form-components/text-field";
import { Button } from "#material-ui/core/";
const NewRequest= () => {
return (
<div>
<TextFieldComponent
name='firstName'
label='First Name'
size='small'
variant='filled'
/>
<br />
<br />
<Button type='submit' variant='contained'>
Submit
</Button>
</div>
);
};
export default NewRequest;
Now pushing that component into an index.js file to render a form:
import React from "react";
import NewVendorForm from "../components/new-vendor-request";
import { useForm } from "react-hook-form";
const Home = () => {
const { handleSubmit } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<NewVendorForm />
</form>
);
};
export default Home;
I'm stumped as to why this way would
a) customise my TextField in my form as intended
b) but not log my data as requested
I'm sure there is a very valid, basic reason as to why and it is my lack of understanding of console logging, but am in need of help to resolve!
Many thanks in advance.
The issue is that, in the refactored code, you're calling useForm twice, each of which generates a different control and data. You probably want to call useForm at the top level only, and pass in whatever you need (in particular control) to the form fields.
const Home = () => {
const { handleSubmit, control } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<NewVendorForm control={control} />
</form>
);
};
const NewRequest= ({control}) => {
return (
<div>
<TextFieldComponent
name='firstName'
label='First Name'
size='small'
variant='filled'
control={control}
/>
<br />
<br />
<Button type='submit' variant='contained'>
Submit
</Button>
</div>
);
};
const TextFieldComponent = (props) => {
const { name, label, size, variant, control } = props;
return (
<div>
<Controller
control={control}
name={name}
render={({ field: { onChange, onBlur, value, ref } }) => (
<TextField
label={label}
variant={variant}
size={size}
onBlur={onBlur}
onChange={onChange}
checked={value}
inputRef={ref}
/>
)}
/>
</div>
);
};

Formik form does not recognize Material ui Button

I am building a login form with Formik with Materail UI, but Formik doesn't recognize Button of Material UI. If I replace the Button with html button everything works. Could anybody explain why it's not working with the Button component. Below is my code:
import React, { ReactElement } from "react";
import TextField from "#material-ui/core/TextField";
import FormControl from "#material-ui/core/FormControl";
import { Formik, Form } from "formik";
import { makeStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Box from "#material-ui/core/Box";
const useStyles = makeStyles((theme) => ({
root: {
margin: theme.spacing(1),
width: 200,
display: "flex",
},
input: {
marginTop: 5,
marginBottom: 5,
},
}));
interface Props {}
export default function loginForm({}: Props): ReactElement {
const classes = useStyles();
return (
<Box className={classes.root}>
<Formik
initialValues={{ username: "", password: "" }}
validate={(values) => {
const errors: { username?: string; password?: string } = {};
if (!values.username) {
errors.username = "Required";
} else if (!values.password) {
errors.password = "Required";
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
console.log("values: ", values);
setSubmitting(false);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
}) => (
<form onSubmit={handleSubmit}>
<FormControl>
<TextField
className={classes.input}
error={errors.username ? true : false}
type="username"
name="username"
onChange={handleChange}
onBlur={handleBlur}
value={values.username}
label="Username"
variant="outlined"
helperText={
errors.username && touched.username && errors.username
}
/>
<TextField
className={classes.input}
error={errors.password ? true : false}
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
label="Password"
variant="outlined"
helperText={
errors.password && touched.password && errors.password
}
/>
</FormControl>
<Box display="flex" justifyContent="space-between">
<Button
variant="contained"
color="primary"
disabled={isSubmitting}
>
Submit
</Button>
<Button
variant="contained"
color="secondary"
disabled={isSubmitting}
>
Cancel
</Button>
</Box>
</form>
)}
</Formik>
</Box>
);
}
please note the code above doesn't work, but if you replace Button with button, the form works.
In most browsers, a HTML button by default has the type=submit which means that Formik's submit handler will be called. A Material-UI button does not have this default so the submit handler will never be called. Try adding type=submit to your <Button> props.
(Also, check out Formik's Material-UI integration examples)
You should add the id to the form.
<form onSubmit={handleSubmit} id="myForm">
And bind the form id with submit button
<Button
type="submit"
form="myForm"
>

How to InputRef works in material ui core 3.9.2

In Material ui core 3.9.2
On inputRef={input => {
this.input = input;
}}
Error Shows
TypeError: Cannot set property 'input' of undefined
If we use this.email instead of this.input
Then Error Shows
TypeError: Cannot set property 'email' of undefined
This is TextField Code
<TextField
id="login-email"
label="Email/MobileNo"
required
fullWidth
type="email"
className={classes.textField}
inputRef={el => {
this.input = el;
}}
or
inputRef={el => this.email = el;}
margin="normal"
/>
Here is solution for functional component.
import React, { useRef, Component } from 'react'
import { TextField, Button } from '#material-ui/core'
import SendIcon from '#material-ui/icons/Send'
export default function MultilineTextFields() {
const valueRef = useRef('') //creating a refernce for TextField Component
const sendValue = () => {
return console.log(valueRef.current.value) //on clicking button accesing current value of TextField and outputing it to console
}
return (
<form noValidate autoComplete='off'>
<div>
<TextField
id='outlined-textarea'
label='Content'
placeholder='Write your thoughts'
multiline
variant='outlined'
rows={20}
inputRef={valueRef} //connecting inputRef property of TextField to the valueRef
/>
<Button
variant='contained'
color='primary'
size='small'
endIcon={<SendIcon />}
onClick={sendValue}
>
Send
</Button>
</div>
</form>
)
}
It was this issue
I solve it by changing
From:
import { makeStyles } from '#material-ui/styles';
import { Link } from "react-router-dom";
import TextField from '#material-ui/core/TextField';
import { Button, Grid } from '#material-ui/core';
import { red } from '#material-ui/core/colors';
const useStyles = makeStyles({
container: {
background: red,
},
});
export default function Hook() {
const classes = useStyles();
const [values, setValues] = React.useState({
email: '',
password: '',
});
const handleChange = name => event => {
setValues({ ...values, [name]: event.target.value });
};
const handleSubmit = event => {
event.preventDefault();
// alert(this.password);
console.log("event ", event);
// console.log("E ",this.email)
// console.log("p ",this.password)
// console.log(this.email.value)
// console.log(this.password.value)
};
return <form className={classes.container} validate="true" onSubmit={handleSubmit} autoComplete="off">
<TextField
id="login-email"
label="Email/MobileNo"
required
fullWidth
type="email"
inputRef={el => this.email = el}
onChange={handleChange('email')}
margin="normal"
/>
<TextField
id="login-password"
label="Password"
required
fullWidth
type="password"
inputRef={el => this.password = el}
onChange={handleChange('password')}
margin="normal"
/>
<Grid container className="m-y-20" justify="center">
<Grid item md={5}>
<Button className="login-submit-btn" type="submit">Login</Button>
<Link className="t-d-none" to="/">
<Button className="login-new-btn">Create New Account</Button>
</Link>
</Grid>
<Grid item md={7}>
<span className="p-x-15">
<Link to="/forgopassword" className="black-clr">
Forgot Your Password?
</Link>
</span>
</Grid>
</Grid>
</form>
}
To:
import React from 'react';
import { Link } from "react-router-dom";
import TextField from '#material-ui/core/TextField';
import { Button, Grid } from '#material-ui/core';
class LoginForm extends React.Component {
render() {
const handleSubmit = event => {
event.preventDefault();
// alert(this.password);
console.log("event ", event);
// console.log("E ",this.email)
// console.log("p ",this.password)
console.log(this.email.value)
console.log(this.password.value)
};
return <form validate="true" onSubmit={handleSubmit} autoComplete="off">
<TextField
id="login-email"
label="Email/MobileNo"
required
fullWidth
type="email"
inputRef={el => this.email = el}
margin="normal"
/>
<TextField
id="login-password"
label="Password"
required
fullWidth
type="password"
inputRef={el => this.password = el}
margin="normal"
/>
<Grid container className="m-y-20" justify="center">
<Grid item md={5}>
<Button className="login-submit-btn" type="submit">Login</Button>
<Link className="t-d-none" to="/">
<Button className="login-new-btn">Create New Account</Button>
</Link>
</Grid>
<Grid item md={7}>
<span className="p-x-15">
<Link to="/forgopassword" className="black-clr">
Forgot Your Password?
</Link>
</span>
</Grid>
</Grid>
</form>
}
}
export default LoginForm;
try
<TextField
id="login-email"
label="Email/MobileNo"
required
fullWidth
type="email"
className={classes.textField}
inputRef={input => this.input = input}
margin="normal"
/>
with this you are returning nothing
inputRef={input => {
this.input = input;
}}

Resources