Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] A implementação do componente SearchForm causa recarregamento da página

Olá.

Nessa aula aprendemos a buscar posts baseado em alguma palavra digitada no componente SearchForm. Segue o código copiado da transcrição da aula:

import { Button } from '@/components/Button'
import styles from './searchform.module.css'

export const SearchForm = () => {
    return (<form className={styles.form} action='/'>
        <input 
            name='q' 
            className={styles.input} 
            placeholder='Digite o que você procura' 
        />
        <Button>
            Buscar
        </Button>
    </form>)
}

Do jeito que o componente foi implementado, essa busca irá causar um recarregamento da página, saindo daquele conceito de SPA.

Por favor, gostaria de saber:

  1. no caso de buscas, é assim mesmo que implementamos, fazendo um recarregamento da página?
  2. Teria um jeito de fazer isso mantendo o conceito de SPA? Tentei fazer isso com a ajuda do ChatGPT, usando o evento de onSubmit e o hook useRouter, mas encontrei erros do tipo "Error: NextRouter was not mounted." e acabei desistindo.

Segue o meu código, em que tentei implementar com o useRouter e que está dando erro:

'use client';
import { useRouter } from 'next/router';
import styles from './searchbar.module.css';
import { Prompt } from 'next/font/google';

const prompt = Prompt({
    weight: ['400', '600'],
    subsets: ['latin'],
    display: 'swap',
});

export default function Searchbar() {
    const router = useRouter();

    const searchSubmit = e => {
        e.preventDefault();
        const q = e.target.q.value;
        if (q) {
            router.push({ 
                pathname: '/',
                query: {q}
            })
        }
    }

    return <form
        className={styles.form}
        onSubmit={searchSubmit}
        // action='/'
    >
        <input
            name='q' // name to be displayed in the query string of the URL
            type="text"
            placeholder="Digite o que você procura"
            className={`${styles.input} ${prompt.className}`}
        />
        <button className={`${styles.button} ${prompt.className}`} >Buscar</button>
    </form>
}

Obrigado!

2 respostas
solução!

Bom dia!

É comum que o comportamento padrão de um formulário HTML cause um recarregamento da página quando o formulário é submetido. Isso ocorre porque o atributo action redireciona o navegador para a URL especificada, causando a recarga completa da página, o que vai contra o conceito de SPA (Single Page Application).

Para evitar isso em Next.js, o ideal é manipular a submissão do formulário com JavaScript, como você tentou fazer utilizando o evento onSubmit. O teu código está quase correto, mas o problema está no uso do hook useRouter. No Next.js, quando você está utilizando a versão que suporta "app directory" e "server components", o hook useRouter precisa ser importado de 'next/navigation' ao invés de 'next/router'.

Pelo o que eu lembre, é bom consultar a documentação atualizada.

Isso deve resolver, mas como nao tenho teu código completo nao consigo testar de fato.

Obrigado!

Consertei a importação para usar o next/navigation e corrigi os parâmetros em router.push. Fazendo isso, agora a URL é atualizada e a busca é feita sem a necessidade de recarregar a página.

Segue como ficou o código. Removi o condicional do if para poder retornar todos os posts no caso de uma busca sem nenhum termo:

'use client';
import { useRouter } from 'next/navigation';
import styles from './searchbar.module.css';
import { Prompt } from 'next/font/google';

const prompt = Prompt({
    weight: ['400', '600'],
    subsets: ['latin'],
    display: 'swap',
});

export default function Searchbar({ }) {
    const router = useRouter();

    const searchSubmit = e => {
        e.preventDefault();
        const q = e.target.q.value;
        router.push(`/?q=${q}`);
    }

    return <form
        className={styles.form}
        onSubmit={searchSubmit}
    >
        <input
            name='q'
            type="text"
            placeholder="Digite o que você procura"
            className={`${styles.input} ${prompt.className}`}
        />
        <button className={`${styles.button} ${prompt.className}`} >Buscar</button>
    </form>
}