Tom Wicks
Tom Wicks

Reputation: 1025

What's the best way to fetch data on form submit in Next.js?

I can successfully retrieve the meta data from a url using the below code and Metadata-scaper when it is hard coded. But how would I go about allowing the user to input the link using the text input and fetching the meta data on form submit?

I'm getting confused with passing data to the getStaticProps. Thank you any help be hugely appreciated.

import Head from 'next/head'
import { useState } from 'react';
import styles from '../styles/Home.module.css'
import getMetaData from 'metadata-scraper'

export async function getStaticProps(name) {
  const url = "http://www.bbc.com"
  const data = await getMetaData(url)
  var urlData = JSON.stringify(data);

  if (!urlData) {
    return {
      notFound: true,
    }
  }

  return {
    props: { urlData }, // will be passed to the page component as props
  }
}

export default function Home(urlData) {
  const [name, setName] = useState('');

  const handleSubmit = e => {
    e.preventDefault();
    const data = {
      name,
    };
    getStaticProps(name)
    console.log(data);
  };

  const myData = JSON.parse(urlData.urlData)

  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <form onSubmit={handleSubmit} className={styles.form}>
          <label htmlFor="name">Name:</label>
          <input
            id="name"
            type="text"
            onChange={e => setName(e.target.value)}
          />

          <button type="submit">Send</button>
        </form>
      </main>
      {console.log(myData.title)}
      <table>
        <tr>
          <th>title</th>
          <th>Provider</th>
          <th>Author</th>
          <th>url</th>
          <th>Language</th>
          <th>Published</th>
        </tr>
        <tr>
          <td>{myData.title}</td>
          <td>{myData.provider}</td>
          <td>{myData.author}</td>
          <td>{myData.url}</td>
          <td>{myData.language}</td>
          <td>{myData.published}</td>
        </tr>

      </table>
    </div>
  );
}

Update 3/8/2021 - 15:35 GMT

I've separated out the API Routes to api/meta.js like so but how do I pass the link from the form there?

import getMetaData from 'metadata-scraper'

export default async function handler(req, res) {
  try {
    const url = 'www.bbc.com'
    res.statusCode = 200;
    const data = await getMetaData(url)
    res.end(JSON.stringify(data));
    console.log(data)
    
  }
  catch (error) {
    res.json(error);
    res.status(405).end();
  }
}

Updated index.js

import Head from 'next/head'
import { useState } from 'react';
import styles from '../styles/Home.module.css'
import useSWR from 'swr'

export default function Home() {

  const { data } = useSWR('/api/meta', fetch)
  const [name, setName] = useState('');
  
  const handleSubmit = e => {
    e.preventDefault();
    fetch('/api/meta', {
      method: 'post',
      body: JSON.stringify({
        name: name,
      })
    })
  };

  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <form onSubmit={handleSubmit} className={styles.form}>
          <label htmlFor="name">Name:</label>
          <input
            id="name"
            type="text"
            onChange={e => setName(e.target.value)}
          />

          <button type="submit">Send</button>
        </form>
      </main>
    </div>
  );
}

Upvotes: 2

Views: 7072

Answers (1)

user16435030
user16435030

Reputation:

You're mixing up a couple of things here that's not correct.

getStaticProps should never manually be called. It's called by nextjs during the static site generation (SSG) step in the build process and called only once for each page (unless those pages are generated through revalidate: 10).

More than that your form submit should call a backend API with the data you want submitted. In this case you're confusing client and server side concepts here. That form submit will be executed client side while the getStaticProps will never be executed client side. So you need something to call your backend API.

Nextjs has a built in API that you can use, I recommend that you follow their guide: https://nextjs.org/docs/api-routes/introduction.

getStaticProps should only ever be called once when the page is first rendered, after that if you want to add functionality to the page, specifically for client side, it should be done in the react component only.

// this will execute client side

const Home = (props) => {
  const [formfield1, setFormfield1] = useState('')

  const submit = () => {
    fetch('https://example.com/api', {
      method: 'post',
      body: JSON.stringify({
        formfield1: formfield1,
      })
    }
  }

  return <form onSubmit={(e) => {e.preventDefault(); submit()}>
    // form stuff here
  </form>
}

...

// this will only ever get executed on page generation server side, not ever on form submit

export const getStaticProps = async () => {
  //
}

In nextjs then you want to create a directory called "api" and to put your form submit code in there so you can call your backend API from the client.

Upvotes: 2

Related Questions