I am starting a project with react,nextjs and typescript, I am trying to submit a form to my backend, but when trying to use the function for the call to the function generated with @ urql-codegen I am getting the following warning, formik.esm.js:925 Warning: An unhandled error was caught from submitForm() Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app
and the query but the query does'n trigger
where my error can be i dont know what to do
The code below
import React from 'react';
import { Formik, Form, Field, FormikHelpers } from 'formik';
import Wrapper from '../components/Wrapper';
import InputField from '../components/InputField';
import { toErrorMap } from '../utils/toErrorMap';
import { useRouter } from 'next/router';
import { createUrqlClient } from '../utils/createUrqlClient';
import { withUrqlClient } from "next-urql"
import { Button, LinearProgress, Grid } from '@material-ui/core';
import Paper from '@material-ui/core/Paper';
import { TextField } from 'formik-material-ui';
import { makeStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Typography from '@material-ui/core/Typography';
//import { useLoginUsuarioQuery } from '../generated/graphql';
import { useQuery } from 'urql';
import { useUserByIdQuery } from '../generated/graphql';
const Login: React.FC<{}> = ({ }) => {
const router = useRouter();
const classes = useStyles();
const submitForm = ({username,password}) => {
const [{data}] = useUserByIdQuery({variables:{id:1}});
console.log(data);
}
return (
<Grid container component="main" className={classes.root}>
<Grid item xs={false} sm={4} md={7} className={classes.image}></Grid>
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square >
<div className={classes.paper}>
<Avatar className={classes.avatar}>
M
</Avatar>
<Typography component="h1" variant="h5">
Ingresar
</Typography>
<Formik
initialValues={{ username: '', password: '' }}
onSubmit={(values) => {submitForm(values)}}
>
{({ isSubmitting }) => (
<Form className={classes.form}>
<Field
component={TextField}
name="username"
type="text"
label="username"
variant="outlined"
className={classes.form}
/>
<br />
<Field
component={TextField}
type="password"
label="Password"
name="password"
variant="outlined"
className={classes.form}
/>
{isSubmitting && <LinearProgress />}
<br />
<Button
variant="contained"
color="primary"
disabled={isSubmitting}
type="submit"
className={classes.form}
>
Submit
</Button>
</Form>
)}
</Formik>
</div>
</Grid>
</Grid>
);
}
export default withUrqlClient(createUrqlClient)(Login)
It looks like you're calling
useUserByIdQuery
insidesubmitForm
, which is a callback. By the naming convention the former is a hook which can only be called directly by your component, as per React's "Rules of Hooks" https://reactjs.org/docs/hooks-rules.htmlI see that you're using a query as generated by (maybe) GraphQL Code Generator, which gives you a hook to use for getting a "User by ID". I assume that you'd want to make this call imperatively when a user submits this login form. To achieve this, depending on what you'd like to do, you'll either have to make your query imperatively or add some state.
The former is more likely if you're dealing with login, as I suppose in the future you may want to have a login mutation. In this case you can either use
client.query(...).toPromise()
using theurql
client, but you must pass the query manually, or you can useuseUserByIdQuery
and passpause: true
as a parameter and use the returnedexecuteQuery
function to give it an ID.