Nextjs Portafolio Simple | Ejemplo Práctico de Next.js

En este ejemplo práctico de Nextjs aprenderemos a crear una aplicación simple que nos podrá servir como portafolio para mostrar nuestros trabajos de desarrollo web y también para practicar también conceptos de HTML, CSS, Javascript, React, Bootstrap, y sobre todo Next.js.

Código del ejemplo:
https://github.com/FaztTech/next-simple-portfolio

#nextjs #next #react #reactjs #javascript

What is GEEK

Buddha Community

Nextjs Portafolio Simple | Ejemplo Práctico de Next.js

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Nextjs Portafolio Simple | Ejemplo Práctico de Next.js

En este ejemplo práctico de Nextjs aprenderemos a crear una aplicación simple que nos podrá servir como portafolio para mostrar nuestros trabajos de desarrollo web y también para practicar también conceptos de HTML, CSS, Javascript, React, Bootstrap, y sobre todo Next.js.

Código del ejemplo:
https://github.com/FaztTech/next-simple-portfolio

#nextjs #next #react #reactjs #javascript

Eva  Murphy

Eva Murphy

1625674200

Google analytics Setup with Next JS, React JS using Router Events - 14

In this video, we are going to implement Google Analytics to our Next JS application. Tracking page views of an application is very important.

Google analytics will allow us to track analytics information.

Frontend: https://github.com/amitavroy/video-reviews
API: https://github.com/amitavdevzone/video-review-api
App link: https://video-reviews.vercel.app

You can find me on:
Twitter: https://twitter.com/amitavroy7​
Discord: https://discord.gg/Em4nuvQk

#next js #js #react js #react #next #google analytics

Diego  Elizondo

Diego Elizondo

1652517446

Implementar Una Ruta De Navegación Dinámica En React/NextJS

Las migas de pan son una herramienta de navegación del sitio web que permite a un usuario ver la "pila" de su página actual de cómo está anidada debajo de las páginas principales. Luego, los usuarios pueden regresar a una página principal haciendo clic en el enlace de ruta de navegación asociado. Estas "migajas" aumentan la experiencia del usuario de la aplicación, lo que facilita que los usuarios naveguen por páginas anidadas de manera eficiente y efectiva.

 

Ejemplo de migas de pan

Las migas de pan son lo suficientemente populares como para que, si está creando un panel de control web o una aplicación, haya considerado agregarlas. Generar estos enlaces de migas de pan de manera eficiente y con el contexto apropiado es clave para una experiencia de usuario mejorada.

Construyamos un NextBreadcrumbs componente React inteligente que analice la ruta actual y construya una pantalla de migas de pan dinámicas que pueda manejar rutas tanto estáticas como dinámicas de manera eficiente.

Mis proyectos generalmente giran en torno a Nextjs y MUI (anteriormente Material-UI), por lo que ese es el ángulo desde el que abordaré este problema, aunque la solución debería funcionar para cualquier aplicación relacionada con Nextjs.

#Breadcrumbs de ruta estática

Para empezar, nuestro NextBreadcrumbscomponente solo manejará rutas estáticas, lo que significa que nuestro proyecto solo tiene páginas estáticas definidas en el pagesdirectorio.

Los siguientes son ejemplos de rutas estáticas porque no contienen [s y ]s en los nombres de ruta, lo que significa que la estructura del directorio se alinea 1:1 exactamente con las URL esperadas que sirven.

  • pages/index.js-->/
  • pages/about.js-->/about
  • pages/my/super/nested/route.js-->/my/super/nested/route

La solución se ampliará para manejar rutas dinámicas más adelante.

#Definiendo el Componente Básico

Podemos comenzar con el componente básico que usa el componente MUIBreadcrumbs como línea de base.

import Breadcrumbs from '@mui/material/Breadcrumbs';
import * as React from 'react';

export default function NextBreadcrumbs() {
  return (
    <Breadcrumbs aria-label="breadcrumb" />
  );
}

Lo anterior crea la estructura básica del NextBreadcrumbscomponente React, importa las dependencias correctas y genera un Breadcrumbscomponente MUI vacío.

Luego podemos agregar los next/routerganchos, lo que nos permitirá construir las migas de pan a partir de la ruta actual.

También creamos un Crumbcomponente que se usará para representar cada enlace. Este es un componente bastante tonto por ahora, excepto que mostrará texto normal en lugar de un enlace para la última ruta de navegación.

En una situación como /settings/notifications, se representaría de la siguiente manera:

Home (/ link) > Settings (/settings link) > Notifications (no link)

Esto se debe a que el usuario ya está en la última página de migas de pan, por lo que no es necesario vincular a la misma página. Todas las demás migajas se representan como enlaces en los que se puede hacer clic.

import Breadcrumbs from '@mui/material/Breadcrumbs';
import Link from '@mui/material/Link';
import Typography from '@mui/material/Typography';
import { useRouter } from 'next/router';
import React from 'react';


export default function NextBreadcrumbs() {
  // Gives us ability to load the current route details
  const router = useRouter();
  
  return (
    <Breadcrumbs aria-label="breadcrumb" />
  );
}


// Each individual "crumb" in the breadcrumbs list
function Crumb({ text, href, last=false }) {
  // The last crumb is rendered as normal text since we are already on the page
  if (last) {
  	return <Typography color="text.primary">{text}</Typography>
  }

  // All other crumbs will be rendered as links that can be visited 
  return (
    <Link underline="hover" color="inherit" href={href}>
      {text}
    </Link>
  );
}

Con este diseño, podemos volver a sumergirnos en el NextBreadcrumbscomponente para generar las migas de pan a partir de la ruta. Parte del código existente comenzará a omitirse para mantener las piezas de código más pequeñas. El ejemplo completo se muestra a continuación.

Generaremos una lista de objetos de migas de pan que contienen la información que cada Crumbelemento debe representar. Cada ruta de navegación se creará analizando la propiedad del enrutador NextjsasPath , que es una cadena que contiene la ruta como se muestra en la barra de URL del navegador.

Quitaremos todos los parámetros de consulta, como ?query=value, de la URL para que el proceso de creación de la ruta de navegación sea más sencillo.

export default function NextBreadcrumbs() {
  // Gives us ability to load the current route details
  const router = useRouter();
  
  function generateBreadcrumbs() {
    // Remove any query parameters, as those aren't included in breadcrumbs
    const asPathWithoutQuery = router.asPath.split("?")[0];
	
	// Break down the path between "/"s, removing empty entities
	// Ex:"/my/nested/path" --> ["my", "nested", "path"]
	const asPathNestedRoutes = asPathWithoutQuery.split("/")
												 .filter(v => v.length > 0);
	
	// Iterate over the list of nested route parts and build
	// a "crumb" object for each one.
	const crumblist = asPathParts.map((subpath, idx) => {
	  // We can get the partial nested route for the crumb
	  // by joining together the path parts up to this point.
	  const href = "/" + asPathNestedRoutes.slice(0, idx + 1).join("/");
	  // The title will just be the route string for now
	  const title = subpath;
  	  return { href, text }; 
    })
	
	// Add in a default "Home" crumb for the top-level
	return [{ href: "/", text: "Home" }, ...crumblist];
  }
  
  // Call the function to generate the breadcrumbs list
  const breadcrumbs = generateBreadcrumbs();
  
  return (
    <Breadcrumbs aria-label="breadcrumb" />
  );
}

Con esta lista de migas de pan, ahora podemos renderizarlas usando los componentes Breadcrumbsy . CrumbComo se mencionó anteriormente, solo returnse muestra la parte de nuestro componente por brevedad.

  // ...rest of NextBreadcrumbs component above...
  return (
    {/* The old breadcrumb ending with '/>' was converted into this */}
    <Breadcrumbs aria-label="breadcrumb">
	  {/*
	    Iterate through the crumbs, and render each individually.
		We "mark" the last crumb to not have a link.
      */}
	  {breadcrumbs.map((crumb, idx) => (
	    <Crumb {...crumb} key={idx} last={idx === breadcrumbs.length - 1} />
	  ))}
	</Breadcrumbs>
  );

Esto debería comenzar a generar algunas migas de pan muy básicas, pero que funcionan, en nuestro sitio una vez renderizado; /user/settings/notificationsrepresentaría como

Home > user > settings > notifications

#Memoizing Breadcrumbs generados

Sin embargo, hay una mejora rápida que podemos hacer antes de seguir adelante. En este momento, la lista de migas de pan se recrea cada vez que el componente se vuelve a renderizar, por lo que podemos memorizar la lista de migas de una ruta determinada para ahorrar algo de rendimiento. Para lograr esto, podemos envolver nuestra generateBreadcrumbsllamada de función en el useMemogancho React.

  const router = useRouter();
  
  // this is the same "generateBreadcrumbs" function, but placed
  // inside a "useMemo" call that is dependent on "router.asPath"
  const breadcrumbs = React.useMemo(function generateBreadcrumbs() {
    const asPathWithoutQuery = router.asPath.split("?")[0];
	const asPathNestedRoutes = asPathWithoutQuery.split("/")
												 .filter(v => v.length > 0);

	const crumblist = asPathParts.map((subpath, idx) => {
	  const href = "/" + asPathNestedRoutes.slice(0, idx + 1).join("/");
  	  return { href, text: subpath }; 
    })
	
	return [{ href: "/", text: "Home" }, ...crumblist];
  }, [router.asPath]);
  
  return // ...rest below...

#Mejora de la visualización del texto de la ruta de navegación

Antes de comenzar a incorporar rutas dinámicas, podemos limpiar más esta solución actual al incluir una forma agradable de cambiar el texto que se muestra para cada migaja generada.

En este momento, si tenemos una ruta como /user/settings/notifications, se mostrará:

Home > user > settings > notifications

que no es muy atractivo. Podemos proporcionar una función al NextBreadcrumbscomponente que intentará generar un nombre más fácil de usar para cada uno de estos fragmentos de ruta anidados.


const _defaultGetDefaultTextGenerator= path => path

export default function NextBreadcrumbs({ getDefaultTextGenerator=_defaultGetDefaultTextGenerator }) {
  const router = useRouter();

  // Two things of importance:
  // 1. The addition of getDefaultTextGenerator in the useMemo dependency list
  // 2. getDefaultTextGenerator is now being used for building the text property
  const breadcrumbs = React.useMemo(function generateBreadcrumbs() {
    const asPathWithoutQuery = router.asPath.split("?")[0];
	const asPathNestedRoutes = asPathWithoutQuery.split("/")
												 .filter(v => v.length > 0);

	const crumblist = asPathParts.map((subpath, idx) => {
	  const href = "/" + asPathNestedRoutes.slice(0, idx + 1).join("/");
  	  return { href, text: getDefaultTextGenerator(subpath, href) }; 
    })

	return [{ href: "/", text: "Home" }, ...crumblist];
  }, [router.asPath, getDefaultTextGenerator]);
  
  return ( // ...rest below

y luego nuestro componente principal puede tener algo como lo siguiente, para titular las rutas secundarias, o tal vez incluso reemplazarlas con una nueva cadena.

{/* Assume that `titleize` is written and works appropriately */}
<NextBreadcrumbs getDefaultTextGenerator={path => titleize(path)} />

Esta implementación daría como resultado las siguientes migas de pan. El ejemplo de código completo en la parte inferior tiene más ejemplos de esto.

Home > User > Settings > Notifications

#Nextjs Rutas dinámicas

El enrutador de Nextjs permite incluir rutas dinámicas que usan Pattern Matching para permitir que las URL tengan slugs, UUID y otros valores dinámicos que luego se pasarán a sus vistas.

Por ejemplo, si su aplicación Nextjs tiene un componente de página en pages/post/[post_id].js, las rutas /post/1y /post/abccoincidirán con él.

Para nuestro componente de migas de pan, nos gustaría mostrar el nombre de la publicación asociada en lugar de solo su UUID. Esto significa que el componente deberá buscar dinámicamente los datos de la publicación en función de la ruta de la ruta URL anidada y regenerar el texto de la migaja asociada.

En este momento, si visitas /post/abc, verás migas de pan que parecen

post > abc

pero si la publicación con UUID tiene un título de My First Post, entonces queremos cambiar las migas de pan para decir

post > My First Post

Profundicemos en cómo puede suceder eso usando asyncfunciones.

Enrutador #Nextjs: asPathvspathname

La next/routerinstancia del enrutador en nuestro código tiene dos propiedades útiles para nuestro NextBreadcrumbscomponente; asPathy pathname. El enrutador asPathes la ruta URL como se muestra directamente en la barra de URL del navegador. Es pathnameuna versión más interna de la URL que tiene las partes dinámicas de la ruta reemplazadas por sus [parameter]componentes.

Por ejemplo, considere el camino /post/abcdesde arriba.

El asPathsería /post/abccomo se muestra la URL

El pathnamesería como dicta /post/[post_id]nuestro directoriopages

Podemos usar estas dos variantes de ruta de URL para crear una forma de obtener información dinámicamente sobre la ruta de navegación, de modo que podamos mostrar información contextualmente más apropiada para el usuario.

Están sucediendo muchas cosas a continuación, así que vuelva a leerlo, y las notas útiles a continuación, unas cuantas veces si es necesario.


const _defaultGetTextGenerator = (param, query) => null;
const _defaultGetDefaultTextGenerator = path => path;

// Pulled out the path part breakdown because its
// going to be used by both `asPath` and `pathname`
const generatePathParts = pathStr => {
  const pathWithoutQuery = pathStr.split("?")[0];
  return pathWithoutQuery.split("/")
						 .filter(v => v.length > 0);
}

export default function NextBreadcrumbs({
  getTextGenerator=_defaultGetTextGenerator,
  getDefaultTextGenerator=_defaultGetDefaultTextGenerator
}) {
  const router = useRouter();

  const breadcrumbs = React.useMemo(function generateBreadcrumbs() {
    const asPathNestedRoutes = generatePathParts(router.asPath);
	const pathnameNestedRoutes = generatePathParts(router.pathname);

	const crumblist = asPathParts.map((subpath, idx) => {
	  // Pull out and convert "[post_id]" into "post_id"
	  const param = pathnameNestedRoutes[idx].replace("[", "").replace("]", "");

	  const href = "/" + asPathNestedRoutes.slice(0, idx + 1).join("/");
  	  return {
	  	href, textGenerator: getTextGenerator(param, router.query),
		text: getDefaultTextGenerator(subpath, href)
	  }; 
    })

	return [{ href: "/", text: "Home" }, ...crumblist];
  }, [router.asPath, router.pathname, router.query, getTextGenerator, getDefaultTextGenerator]);
  
  return ( // ...rest below

El asPathdesglose se movió a una generatePathPartsfunción ya que se usa la misma lógica para ambos router.asPathy router.pathname.

Determine el paraméter que se alinea con el valor de la ruta dinámica, por lo que abcdaría como resultado post_id.

El éter de ruta anidado paramy todos los valores de consulta asociados ( router.query) se pasan a un proveedor getTextGeneratorque devolverá un nullvalor o una Promiserespuesta que debería devolver la cadena dinámica para usar en la ruta de navegación asociada.

La useMemomatriz de dependencia tiene más dependencias agregadas; router.pathname, router.queryy getTextGenerator.

Finalmente, necesitamos actualizar el Crumbcomponente para usar este textGeneratorvalor si se proporciona para el objeto migas asociado.

function Crumb({ text: defaultText, textGenerator, href, last=false }) {

  const [text, setText] = React.useState(defaultText);
  
  useEffect(async () => {
    // If `textGenerator` is nonexistent, then don't do anything
    if (!Boolean(textGenerator)) { return; }
	// Run the text generator and set the text again
    const finalText = await textGenerator();
    setText(finalText);
  }, [textGenerator]);

  if (last) {
  	return <Typography color="text.primary">{text}</Typography>
  }

  return (
    <Link underline="hover" color="inherit" href={href}>
      {text}
    </Link>
  );
}

 

Las migas de pan ahora pueden manejar rutas estáticas y rutas dinámicas de forma limpia con el potencial de mostrar valores fáciles de usar. Si bien el código anterior es la lógica comercial del componente, todo esto se puede usar con un componente principal que se parece al ejemplo final a continuación.

#Ejemplo Completo

// NextBreadcrumbs.js

const _defaultGetTextGenerator = (param, query) => null;
const _defaultGetDefaultTextGenerator = path => path;

// Pulled out the path part breakdown because its
// going to be used by both `asPath` and `pathname`
const generatePathParts = pathStr => {
  const pathWithoutQuery = pathStr.split("?")[0];
  return pathWithoutQuery.split("/")
						 .filter(v => v.length > 0);
}

export default function NextBreadcrumbs({
  getTextGenerator=_defaultGetTextGenerator,
  getDefaultTextGenerator=_defaultGetDefaultTextGenerator
}) {
  const router = useRouter();

  const breadcrumbs = React.useMemo(function generateBreadcrumbs() {
    const asPathNestedRoutes = generatePathParts(router.asPath);
	const pathnameNestedRoutes = generatePathParts(router.pathname);

	const crumblist = asPathParts.map((subpath, idx) => {
	  // Pull out and convert "[post_id]" into "post_id"
	  const param = pathnameNestedRoutes[idx].replace("[", "").replace("]", "");

	  const href = "/" + asPathNestedRoutes.slice(0, idx + 1).join("/");
  	  return {
	  	href, textGenerator: getTextGenerator(param, router.query),
		text: getDefaultTextGenerator(subpath, href)
	  }; 
    })

	return [{ href: "/", text: "Home" }, ...crumblist];
  }, [router.asPath, router.pathname, router.query, getTextGenerator, getDefaultTextGenerator]);
  
  return (
    <Breadcrumbs aria-label="breadcrumb">
	  {breadcrumbs.map((crumb, idx) => (
	    <Crumb {...crumb} key={idx} last={idx === breadcrumbs.length - 1} />
	  ))}
	</Breadcrumbs>
  );
}


function Crumb({ text: defaultText, textGenerator, href, last=false }) {

  const [text, setText] = React.useState(defaultText);
  
  useEffect(async () => {
    // If `textGenerator` is nonexistent, then don't do anything
    if (!Boolean(textGenerator)) { return; }
	// Run the text generator and set the text again
    const finalText = await textGenerator();
    setText(finalText);
  }, [textGenerator]);

  if (last) {
  	return <Typography color="text.primary">{text}</Typography>
  }

  return (
    <Link underline="hover" color="inherit" href={href}>
      {text}
    </Link>
  );
}

y luego se puede ver un ejemplo de este NextBreadcrumbsuso a continuación. Tenga en cuenta que useCallbackse utiliza para crear solo una referencia a cada función auxiliar, lo que evitará que se vuelvan a procesar innecesariamente las migas de pan cuando/si el componente de diseño de página se vuelve a procesar. También puede mover esto al alcance de nivel superior del archivo, pero no me gusta contaminar el alcance global de esa manera.

// MyPage.js (Parent Component)

import React from 'react';
import NextBreadcrumbs from "./NextBreadcrumbs";


function MyPageLayout() {

  // Either lookup a nice label for the subpath, or just titleize it
  const getDefaultTextGenerator = React.useCallback((subpath) => {
    return {
	  "post": "Posts",
	  "settings": "User Settings",
	}[subpath] || titleize(subpath);
  }, [])
  
  // Assuming `fetchAPI` loads data from the API and this will use the
  // parameter name to determine how to resolve the text. In the example,
  // we fetch the post from the API and return it's `title` property
  const getTextGenerator = React.useCallback((param, query) => {
    return {
	  "post_id": () => await fetchAPI(`/posts/${query.post_id}/`).title,
	}[param];
  }, []);

  return () {
    <div>
	  {/* ...Whatever else... */}
	  <NextBreadcrumbs
	    getDefaultTextGenerator={getDefaultTextGenerator}
		getTextGenerator={getTextGenerator}
	  />
	  {/* ...Whatever else... */}
	</div>
  }

}

Esta es una de mis publicaciones más profundas y técnicas, así que espero que la hayas disfrutado, y por favor comenta o comunícate para que pueda garantizar la coherencia y la corrección. Con suerte, esta publicación le enseñó algunas estrategias o conceptos sobre Nextjs.

Fuente: https://hackernoon.com/implement-a-dynamic-breadcrumb-in-reactnextjs

#react #nextjs 

Eva  Murphy

Eva Murphy

1625751960

Laravel API and React Next JS frontend development - 28

In this video, I wanted to touch upon the functionality of adding Chapters inside a Course. The idea was to not think much and start the development and pick up things as they come.

There are places where I get stuck and trying to find answers to it up doing what every developer does - Google and get help. I hope this will help you understand the flow and also how developers debug while doing development.

App url: https://video-reviews.vercel.app
Github code links below:
Next JS App: https://github.com/amitavroy/video-reviews
Laravel API: https://github.com/amitavdevzone/video-review-api

You can find me on:
Twitter: https://twitter.com/amitavroy7​
Discord: https://discord.gg/Em4nuvQk

#next js #api #react next js #next #frontend #development