¿Hay alguna manera de que podamos tener un estado de carga similar a cuando se obtienen datos en el client-side ?
La razón por la que me gustaría un estado de carga es tener algo así como un esqueleto de carga con, por ejemplo react-loading-skeleton
En el lado del cliente podríamos hacer:
import useSWR from 'swr' const fetcher = (url) => fetch(url).then((res) => res.json()) function Profile() { const { data, error } = useSWR('/api/user', fetcher) if (error) return <div>failed to load</div> if (!data) return <div>loading...</div> return <div>hello {data.name}!</div> }Pero para SSR (getServerSideProps) no puedo averiguar si eso es factible, por ejemplo, ¿podríamos tener un estado de carga?
function AllPostsPage(props) { const router = useRouter(); const { posts } = props; function findPostsHandler(year, month) { const fullPath = `/posts/${year}/${month}`; router.push(fullPath); } if (!data) return <div>loading...</div>; // Would not work with SSR return ( <Fragment> <PostsSearch onSearch={findPostsHandler} /> <PosttList items={posts} /> </Fragment> ); } export async function getServerSideProps() { const posts = await getAllPosts(); return { props: { posts: posts, }, }; } export default AllPostsPage; Recientemente, Next.js ha lanzado getServerSideProps should support props value as Promise https://github.com/vercel/next.js/pull/28607 Con eso podemos hacer una promesa, pero no estoy seguro de cómo implementarla y tener un estado de carga o si eso es incluso alcanzable. Su ejemplo muestra:
export async function getServerSideProps() { return { props: (async function () { return { text: 'promise value', } })(), } }Puede modificar el componente _app.js para mostrar un componente de carga mientras getServerSideProps realiza un trabajo asíncrono como una búsqueda, como se muestra aquí https://stackoverflow.com/a/60756105/13824894 . Esto se aplicará en cada transición de página dentro de su aplicación.
Todavía puede usar su lógica de carga del lado del cliente de forma independiente.
puede establecer el estado de carga en _app.js
import Router from "next/router"; export default function App({ Component, pageProps }) { const [loading, setLoading] = React.useState(false); React.useEffect(() => { const start = () => { console.log("start"); setLoading(true); }; const end = () => { console.log("findished"); setLoading(false); }; Router.events.on("routeChangeStart", start); Router.events.on("routeChangeComplete", end); Router.events.on("routeChangeError", end); return () => { Router.events.off("routeChangeStart", start); Router.events.off("routeChangeComplete", end); Router.events.off("routeChangeError", end); }; }, []); return ( <> {loading ? ( <h1>Loading...</h1> ) : ( <Component {...pageProps} /> )} </> ); }Todavía no he probado esta función, pero en teoría creo que debería funcionar. Si todo lo que desea es que el lado del cliente acceda a una promesa a través de los accesorios del servidor, intente lo siguiente. Básicamente, sus accesorios son una función lambda asíncrona, por lo que realiza cualquier trabajo necesario, por ejemplo, obtener datos, etc. dentro de él, por lo que el lado del cliente debe acceder a los accesorios como una promesa y esperarlos.
export async function getServerSideProps() { return { props: (async function () { const posts = await getAllPosts(); return { posts: posts, } })(), } } //then on client-side you can do the following or similar to set loading state function MyComponent(props) { const [isLoading, setIsLoading] = useState(false); const [posts, setPosts] = useState({}); useEffect(async () => { setIsLoading(true); const tempPosts = await props?.posts; setPosts(posts); setIsLoading(false); }, []) return ( {isLoading && <div>loading...</div>} ); } export default MyComponent;