Catégories
JavaScript

Next.js

NextJs est un Framework React qui popularise le SSR (Server Side Rendering) de webapps React de par sa facilité de prise en main (tuto officiel très clean).

Avantages

Next.js rend le routage intuitif, car par convention, le framework établi une correspondance directe entre un fichier JavaScript (du dossier /pages) et une URL.
Le fichier /pages/toto.jsx générera automatiquement l’URL http://monsite/toto.

Les intérêts de cette solution:

  • SSR out of the box
  • routage intuitif
  • learning curve très raide pour les développeurs React et une prise en main rapide grâce à leurs tuto
  • utilise Webpack 4 et son HMR (Hot Module Replacement), qui permet de développer et de voir ses modification appliquées quasi instantanément dans le navigateur, sans perdre le state des composants
  • système de plugins officiels intéressants (SEO, offline, Webworkers etc.)

Routing

Une URL est crée automatiquement dès qu’on dépose un fichier JS ou JSX dans le dossier /pages/ (par convention ce dossier doit s’appeler pages).
Next nécessite que le fichier JavaScript contienne un export de composant React pour pouvoir effectuer son rendu.
Pour les éléments statiques (images, css et autres) il existe également un dossier /static/ réservé a cet effet.

Navigation

La navigation est simplifiée par l’usage de composants Nextjs Link et Router auxquels on peut associer l’objet URL.

<Link as={`/route-a-afficher/${show.id}`} href={`/route-correspondant-fichier?id=${show.id}`}>
  • la prop href permet au framework de faire le lien entre l’URL et les fichiers JS contenu dans le dossier pages
  • la prop as permet de créer et d’afficher dans le HTML résultant un href alias (ici le lien pointera vers /p/xxx), qu’il faudra traiter coté back (méthode render de l’API next).

Le HOC withRouter permet de récupérer dans nos composants, via les props du composant React (props.router):

  • les informations de routage (voir l’API)
  • des méthodes de pushState, replaceState et beforePopState

Cycle de vie du Router

Le Router de Next.js propose un ensemble d’évènements qu’il est possible d’écouter :

  • routeChangeStart(url)
  • routeChangeComplete(url)
  • routeChangeError(err, url)
  • beforeHistoryChange(url)
  • hashChangeStart(url)
  • hashChangeComplete(url)

Server Side Rendering

Dans la plupart des cas, des routes simples ne suffiront pas, et on aura des URL qui ne vont plus correspondre à des fichiers présents dans /pages, comme par exemple lorsqu’on utilise les props « as » du composant <Link/>.
Il est alors nécessaire d’utiliser un routage coté serveur, voici un exemple en Node/Express (selon doc):

const next = require('next')
const app = next({ dev })
const handle = app.getRequestHandler()

app
  .prepare()
  .then(() => {
    const server = express()
    server.get("/produits?/:univers/:category*?", (req, res) => {
      const actualPage = "/produits"
      const queryParams = { ...req.params }
      app.render(req, res, actualPage, queryParams)
    });
....

Appels Ajax

Si on suit le tuto de Next.js, on s’aperçoit qu’ils utilisent la librairie unfetch (très légère) et son compagnon isomorphic-unfetch, mais on peut bien sure utiliser des librairies plus connues comme isomorphic-fetch ou disposant de plus de fonctionnalités comme Axios (permet d’annuler les requêtes Ajax).

la méthode getInitialProps

Avec Next.js, on utilise la méthode statique getInitialProps qui permet comme son nom l’indique, de charger les props du composant avec le résultat de la requête Ajax. Il est possible d’utiliser cette méthode de 2 façons:

  • soit dans un composant React (qui possède donc un lifecyle), en définissant cette méthode: static async getInitialProps({ req }) {...
  • soit en définissant un lifecycle methode pris en charge par le framework Nexjs, pour un composant stateless (ici nommé MaPage): MaPage.getInitialProps = async ({ req }) => {...

propriétés de l’objet context

La méthode getInitialProps reçoit en paramètre un objet context  (paramètre req dans les 2 ex ci-dessus) qui contient les informations de routage:

  • pathname – chemin next (correspondant au fichier js)
  • asPath – URL complète telle que visible dans le navigateur incluant la query string
  • queryquery string de l’URL parsé dans un objet
  • req – objet request HTTP (serveur uniquement)
  • res – objet response HTTP (serveur uniquement)
  • jsonPageRes – objet Fetch Response (client uniquement)
  • err – objet Error si une erreur intervient lors du render

Styling

CSS avec styled-jsx

Nextjs a fait le choix d’utiliser une des solution CSS-in-JS, styled-jsx parmi les nombreuses solutions existantes, qui permet d’avoir des styles scopés au niveau du composant, et surtout d’appliquer les styles lors du rendu coté serveur.
Les styles ne se propagent pas aux composants enfants par défaut, mais il est possible de forcer la propagation en utilisant l’attribut global.
Styled-jsx est traité dans Nextjs par un plugin Babel styled-jsx/babel.

L’utilisation est encore une fois très intuitive, car il suffit d’écrire ses styles directement dans des balises <style jsx>  à l’intérieur de ses composants en utilisant la syntaxe template strings:

<style jsx>{`
    h1, a {
    font-family: "Arial";
  }
`}</style>

CSS classique

La doc Next.js recommande d’utiliser styled-jsx pour le styling, mais il est tout à fait possible d’importer du CSS, SASS, LESS ou Stylus grâce à des plugins Next.

De plus si on souhaite utiliser une bibliothèque CSS, styled-jsx va automatiquement prefixer les noms de classe dans le HTML rendu, ce créera des interférences.
On peut éviter cela en utilisant l’attribut optionCLassName au lieu du classique class.

<Select optionClassName="react-select" />

Create Next App

create-next-app (équivalent du create-react-app) est un outil qui fourni un squelette de projet Next.js/React/Redux, parfait pour voir rapidement les branchements entre ces outils 🙂

Concernant Material UI, il y a un exemple de projet Nexjs/MaterialUI ainsi qu’une doc SSR Material UI.

Versions Next.js

Chaque version de Next.js apportant son lot de nouveautés, j’ai extrait ici celles qui me paraissaient les plus importantes, et ne pas oublier de se référer au guide de migration.