Soy nuevo en Next.js y estoy tratando de comprender la estructura sugerida y tratar con datos entre páginas o componentes.
Por ejemplo, dentro de mi página home.js , busco una API interna llamada /api/user.js que devuelve algunos datos de usuario de MongoDB. Estoy haciendo esto usando fetch() para llamar a la ruta API desde getServerSideProps() , que pasa varios accesorios a la página después de algunos cálculos.
Según tengo entendido, esto es bueno para el SEO, ya que los accesorios se recuperan/modifican en el lado del servidor y la página los prepara para mostrarse. Pero luego leí en la documentación de Next.js que no debe usar fetch() para todas las rutas API en getServerSideProps() . Entonces, ¿qué se supone que debo hacer para cumplir con las buenas prácticas y el buen SEO?
La razón por la que no estoy haciendo los cálculos requeridos para home.js en la ruta API en sí es que necesito más datos genéricos de esta ruta API, ya que también los usaré en otras páginas.
También tengo que considerar el almacenamiento en caché, que del lado del cliente es muy sencillo usando SWR para obtener una API interna, pero del lado del servidor aún no estoy seguro de cómo lograrlo.
home.js :
export default function Page({ prop1, prop2, prop3 }) { // render etc. } export async function getServerSideProps(context) { const session = await getSession(context) let data = null var aArray = [], bArray = [], cArray = [] const { db } = await connectToDatabase() function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex; while (0 !== currentIndex) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } if (session) { const hostname = process.env.NEXT_PUBLIC_SITE_URL const options = { headers: { cookie: context.req.headers.cookie } } const res = await fetch(`${hostname}/api/user`, options) const json = await res.json() if (json.data) { data = json.data } // do some math with data ... // connect to MongoDB and do some comparisons, etc.Pero luego leí en la documentación de Next.js que no debe usar
fetch()para todas las rutas API engetServerSideProps().
Desea usar la lógica que está en su ruta de API directamente en getServerSideProps , en lugar de llamar a su API interna. Esto se debe a que getServerSideProps se ejecuta en el servidor al igual que las rutas de la API (no tendría sentido realizar una solicitud desde el servidor al propio servidor). Puede leer desde el sistema de archivos o acceder a una base de datos directamente desde getServerSideProps .
De la documentación de Next.js getServerSideProps :
Puede ser tentador buscar una ruta API cuando desea obtener datos del servidor y luego llamar a esa ruta API desde
getServerSideProps. Este es un enfoque innecesario e ineficiente, ya que hará que se realice una solicitud adicional debido a que tantogetServerSidePropscomo API Routes se ejecutan en el servidor.(...) En su lugar, importe directamente la lógica utilizada dentro de su API Route en
getServerSideProps. Esto podría significar llamar a un CMS, una base de datos u otra API directamente desde dentro degetServerSideProps.
(Tenga en cuenta que lo mismo se aplica cuando se usan los métodos getStaticProps / getStaticPaths )
Aquí hay un pequeño ejemplo de refactorización que le permite reutilizar la lógica de una ruta API en getServerSideProps .
Supongamos que tiene esta ruta API simple.
// pages/api/user export default async function handler(req, res) { // Using a fetch here but could be any async operation to an external source const response = await fetch(/* external API endpoint */) const jsonData = await response.json() res.status(200).json(jsonData) } Puede extraer la lógica de recuperación a una función separada (todavía puede mantenerla en api/user si lo desea), que aún se puede utilizar en la ruta API.
// pages/api/user export async function getData() { const response = await fetch(/* external API endpoint */) const jsonData = await response.json() return jsonData } export default async function handler(req, res) { const jsonData = await getData() res.status(200).json(jsonData) } Pero también le permite reutilizar la función getData en getServerSideProps .
// pages/home import { getData } from './api/user' //... export async function getServerSideProps(context) { const jsonData = await getData() //... }Solo intente usar useSWR , ejemplo a continuación
import useSWR from 'swr' import React from 'react'; //important to return only result, not Promise const fetcher = (url) => fetch(url).then((res) => res.json()); const Categories = () => { //getting data and error const { data, error } = useSWR('/api/category/getCategories', fetcher) if (error) return <div>Failed to load</div> if (!data) return <div>Loading...</div> if (data){ // {data} is completed, it's ok! //your code here to make something with {data} return ( <div> //something here, example {data.name} </div> ) } } export default Categories Tenga en cuenta que fetch solo admite URL absolutas , es por eso que no me gusta usarlo.
PD De acuerdo con los documentos , incluso puede usar useSWR con SSR .
Quiere usar la lógica que está en su ruta API directamente en getServerSideProps, en lugar de llamar a su API interna. Esto se debe a que getServerSideProps se ejecuta en el servidor al igual que las rutas de la API (no tendría sentido realizar una solicitud desde el servidor al propio servidor). Puede leer desde el sistema de archivos o acceder a una base de datos directamente desde getServerSideProps
como admito que usted dice que es correcto, pero por cierto existe un problema. Supongamos que tiene su backend escrito y que sus api están protegidas, por lo que obtener la lógica de un backend seguro y escrito parece ser molesto y perder tiempo y energía. Otra desventaja es que por obteniendo la lógica del backend, debe reescribir su propio código para manejar los errores y autenticar los usuarios y validar las solicitudes de los usuarios que existen en su backend escrito. me pregunto si es posible llamar a api dentro de nextjs sin buscar la lógica de middlewars? la respuesta es positiva aquí está mi solución: npm i node-mocks-http
import httpMocks from "node-mocks-http"; import newsController from "./api/news/newsController"; import logger from "../middlewares/logger"; import dbConnectMid from "../middlewares/dbconnect"; import NewsCard from "../components/newsCard"; export default function Home({ news }) { return ( <section> <h2>Latest News</h2> <NewsCard news={news} /> </section> ); } export async function getServerSideProps() { let req = httpMocks.createRequest(); let res = httpMocks.createResponse(); async function callMids(req, res, index, ...mids) { index = index || 0; if (index <= mids.length - 1) await mids[index](req, res, () => callMids(req, res, ++index, ...mids)); } await callMids( req, res, null, dbConnectMid, logger, newsController.sendAllNews ); return { props: { news: res._getJSONData() }, }; } NOTA importante: no se olvide de usar await await next() en lugar de next() si usa mi código en todos sus middlewares o de lo contrario obtiene un error. otra solución: la próxima conexión tiene un método run que hace algo como mycode, pero personalmente tuve algunos problemas aquí está su enlace: el siguiente método de ejecución de conexión para llamar a las próximas api en serverSideProps