Reputation: 4352
I'm new @frontend and found it a bit challenging creating a simple search form in Next.js
with using Formik
and return data fetched from my own API back on page. As there are not so much relevant information about, or there is, but it doesn't cover the whole process, so I decided to create this question.
What am I dealing with:
Architecture:
Front send request (based on form input) -> Server received it (operates with it) and respond with json
object -> Front takes it, and shows result back on page.
A simple node.js express server with one-route (localhost:port/users/:id) when you request it like ./users/100
it returns json
with {id}+1 increment, like {id:101}
, example code below:
var express = require('express');
var router = express.Router();
/* CORS ARE FINE */
router.get('/:id', function(req, res) {
res.json({id: parseInt(req.params.id)+1});
});
module.exports = router;
I have already write MyForm
component and insert it on my Home page. Here is a code of MyForm
component:
import React from 'react';
import fetch from 'isomorphic-unfetch'
import { Formik, Form, Field } from 'formik';
import { TextField } from 'formik-material-ui';
import Button from "@material-ui/core/Button";
const MyForm = () => (
<Formik
initialValues={{ text: '', password: '' }}
onSubmit={ async (values, { setSubmitting }) => {
const res = await fetch(`http://localhost:8000/users/${values.text}`, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}}).then(response => response.json());
console.log(res);
//props = res;
//return props;
setTimeout(() => {
alert(JSON.stringify(res, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ isSubmitting }) => (
<Form>
<Field
name="text"
label="Text"
type="text"
variant="outlined"
component={TextField}
/>
<Button
type="submit"
variant="contained"
color="primary"
disabled={isSubmitting}
>
Submit
</Button>
</Form>
)}
</Formik>
);
export default MyForm
As for now, myForm works fine, necessary data received from API via submitting form. The result is stored as res
variable and showed as a popup on the page.
But I want to see it, back on page. Like this:
There are not so much tutorials in the web that cover this process step-by-step. I know that in Next.js
fetched data received via getInitialProps
. (But there are no examples with form submitting)
I place my component on page:
export default function Index() {
return (
<Container maxWidth="sm">
<Box my={4}>
<Form />
<Here is an element with search form results />
</Box>
</Container>
);
}
And then I read that I can't return props from child component back to parent. Or can I? I also can't place res
variable as a component value inside or outside my form:
So what I should do now? Anyway I haven't find any relevant example in Formik
tutorial. I understand that it is somehow connected with state
manipulation like componentDiDMount
and that's why frontend devs using modules like Redux
. But can someone explain me, what am I doing wrong?
Also, if you have any relevant information and want to give me some advice or share it (like Formik is useless in this case, you should use X
instead) don't be shy, just post it. I'll check it out and upvote.
According to @Shyam answer I updated my code. As for now, form has the following code:
const MyForm = (props) => (
<Formik>
...
onSubmit={ async (values, { setSubmitting }) => {
const res = await fetch(`http://localhost:8000/users/${values.text}`, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}}).then(response => response.json());
console.log(res);
setSubmitting(false);
props.myCallbackFunction(res);
}}
...
and index.js
according the below recommendation,
In this case React
return me an error, connected with props
but the form submission works fine. Guess I could found relevant information here:
https://reacttricks.com/sharing-global-data-in-next-with-custom-app-and-usecontext-hook/
Upvotes: 5
Views: 6207
Reputation: 114
One way would be to send a callback function to MyForm as a prop and have it called with res after the fetched result is received.
export default function Index() {
const [result, setResult] = useState(null)
const callMeOnRes = (data) => {
setResult(data)
}
return (
<Container maxWidth="sm">
<Box my={4}>
<Form myCallbackFunction={(res) => callMeOnRes(res)} />
{result && <div>{result}</div>}
<Here is an element with search form results />
</Box>
</Container>
);
}
Inside MyForm, after the console log you call props.myCallbackFunction(res)
.
The best way would be to decouple the api call and the frontend logic and using some state management for loading, error, called states. Ideally you should'nt be using setTimeouts in such scenarios.
Hope this helped.
Upvotes: 2