AlexZeDim
AlexZeDim

Reputation: 4352

How to return API (fetched) data from Formik Submit in Next.js

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:

  1. separated front-end and back-end based API on express (both on localhost right now)
  2. React (+ dom) & Next.js
  3. React Material-UI
  4. Formik

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;

server

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.

res

But I want to see it, back on page. Like this:

res

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:

enter image description here

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

Answers (1)

Shyam
Shyam

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

Related Questions