So erstellen Sie eine Kommentar-Engine mit Next.js und Sanity

Avatar of Bryan Robinson
Bryan Robinson am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Eines der Argumente gegen den Jamstack-Ansatz zum Erstellen von Websites ist, dass die Entwicklung von Funktionen komplex wird und oft eine Reihe anderer Dienste erfordert. Nehmen wir zum Beispiel Kommentare. Um Kommentare für eine Jamstack-Site einzurichten, benötigen Sie oft eine Drittanbieterlösung wie Disqus, Facebook oder sogar nur einen separaten Datenbankdienst. Diese Drittanbieterlösung bedeutet normalerweise, dass Ihre Kommentare getrennt von ihren Inhalten leben.

Wenn wir Drittanbietersysteme nutzen, müssen wir mit den Kompromissen der Nutzung fremden Codes leben. Wir erhalten eine Plug-and-Play-Lösung, aber zu welchem ​​Preis? Anzeigen, die unseren Nutzern angezeigt werden? Unnötiger JavaScript, den wir nicht optimieren können? Die Tatsache, dass der Kommentarinhalt jemand anderem gehört? Das sind definitiv Dinge, die es wert sind, in Betracht gezogen zu werden.

Monolithische Dienste, wie WordPress, haben dies gelöst, indem alles unter derselben Anwendung untergebracht wurde. Was wäre, wenn wir unsere Kommentare in derselben Datenbank und im CMS wie unsere Inhalte unterbringen, sie auf dieselbe Weise abfragen könnten, wie wir unsere Inhalte abfragen, und sie mit demselben Framework im Frontend anzeigen?

Dies würde diese spezielle Jamstack-Anwendung sowohl für unsere Entwickler als auch für unsere Redakteure wesentlich kohärenter machen.

Lassen Sie uns unsere eigene Kommentar-Engine erstellen

In diesem Artikel werden wir Next.js und Sanity.io verwenden, um eine Kommentar-Engine zu erstellen, die diese Anforderungen erfüllt. Eine einheitliche Plattform für Inhalte, Redakteure, Kommentatoren und Entwickler.

Warum Next.js?

Next.js ist ein Meta-Framework für React, das vom Team bei Vercel entwickelt wurde. Es verfügt über integrierte Funktionen für serverlose Funktionen, statische Seitengenerierung und serverseitiges Rendering.

Für unsere Arbeit werden wir hauptsächlich seine integrierten „API-Routen“ für serverlose Funktionen und seine statischen Seitengenerierungsfunktionen nutzen. Die API-Routen vereinfachen das Projekt erheblich, aber wenn Sie auf etwas wie Netlify bereitstellen, können diese in serverlose Funktionen umgewandelt werden oder wir können das `next-on-netlify`-Paket von Netlify verwenden.

Diese Schnittstelle aus statischen, serverseitig gerenderten und serverlosen Funktionen macht Next.js zu einer großartigen Lösung für ein Projekt wie dieses.

Warum Sanity?

Sanity.io ist eine flexible Plattform für strukturierte Inhalte. Im Kern ist es ein Datenspeicher, der Entwickler dazu ermutigt, Inhalte als strukturierte Daten zu betrachten. Es wird oft mit einer Open-Source-CMS-Lösung namens Sanity Studio kombiniert.

Wir werden Sanity verwenden, um die Inhalte des Autors zusammen mit benutzergenerierten Inhalten wie Kommentaren zu speichern. Letztendlich ist Sanity eine Inhaltsplattform mit einer starken API und einem konfigurierbaren CMS, das die Anpassung ermöglicht, die wir benötigen, um diese Dinge zu verbinden.

Sanity und Next.js einrichten

Wir werden bei diesem Projekt nicht bei Null anfangen. Wir werden zunächst den einfachen Blog-Starter von Vercel verwenden, um mit einer Next.js- und Sanity-Integration zu arbeiten. Da das Vercel-Starter-Repository das Frontend und Sanity Studio getrennt hat, habe ich ein vereinfachtes Repository erstellt, das beides enthält.

Wir werden dieses Repository klonen und es verwenden, um unsere Kommentarbasis zu erstellen. Möchten Sie den endgültigen Code sehen? Dieser „Starter“ hilft Ihnen, das Repository, das Vercel-Projekt und das Sanity-Projekt miteinander zu verbinden.

Das Starter-Repository besteht aus zwei Teilen: dem Frontend, das von Next.js angetrieben wird, und Sanity Studio. Bevor wir weitermachen, müssen wir diese lokal zum Laufen bringen.

Um zu beginnen, müssen wir unsere Inhalte und unser CMS für Next einrichten, um die Daten zu verbrauchen. Zuerst müssen wir die erforderlichen Abhängigkeiten für die Ausführung des Studios und die Verbindung zur Sanity-API installieren.

# Install the Sanity CLI globally
npm install -g @sanity/cli
# Move into the Studio directory and install the Studio's dependencies
cd studio
npm install

Sobald diese installiert sind, können wir von Verzeichnis /studio aus ein neues Projekt mit der CLI einrichten.

# If you're not logged into Sanity via the CLI already
sanity login
# Run init to set up a new project (or connect an existing project)
sanity init

Der Befehl `init` stellt uns einige Fragen, um alles einzurichten. Da der Studio-Code bereits einige Konfigurationswerte enthält, fragt die CLI, ob wir ihn neu konfigurieren möchten. Das möchten wir.

Von dort aus wird gefragt, mit welchem ​​Projekt eine Verbindung hergestellt werden soll oder ob ein neues Projekt konfiguriert werden soll.

Wir werden ein neues Projekt mit einem aussagekräftigen Projektnamen konfigurieren. Es wird gefragt, wie der zu erstellende „Dataset“ genannt werden soll. Dies ist standardmäßig „production“, was in Ordnung ist, kann aber mit einem Namen überschrieben werden, der für Ihr Projekt sinnvoll ist.

Die CLI wird die Datei ~/studio/sanity.json mit der Projekt-ID und dem Dataset-Namen ändern. Diese Werte sind später wichtig, also halten Sie diese Datei griffbereit.

Vorerst sind wir bereit, das Studio lokal auszuführen.

# From within /studio
npm run start

Nachdem das Studio kompiliert wurde, kann es im Browser unter https://:3333 geöffnet werden.

Zu diesem Zeitpunkt ist es sinnvoll, in den Admin-Bereich zu gehen und einige Testinhalte zu erstellen. Damit das Frontend richtig funktioniert, benötigen wir mindestens einen Blogbeitrag und einen Autor, aber zusätzliche Inhalte sind immer gut, um ein Gefühl für die Dinge zu bekommen. Beachten Sie, dass die Inhalte in Echtzeit mit dem Datenspeicher synchronisiert werden, auch wenn Sie vom Studio auf localhost aus arbeiten. Sie werden sofort abrufbar sein. Vergessen Sie nicht, auf „Publish“ zu klicken, damit die Inhalte öffentlich zugänglich sind.

Sobald wir einige Inhalte haben, ist es an der Zeit, unser Next.js-Projekt zu starten.

Einrichtung mit Next.js

Die meisten für Next.js benötigten Dinge sind im Repository bereits eingerichtet. Das Wichtigste, was wir tun müssen, ist die Verbindung unseres Sanity-Projekts mit Next.js. Dazu gibt es ein Beispiel für Umgebungsvariablen in /blog-frontent/.env.local.example. Entfernen Sie .example aus dieser Datei und ändern Sie dann die Umgebungsvariablen mit den richtigen Werten.

Wir benötigen einen API-Token von unserem Sanity-Projekt. Um diesen Wert zu erstellen, gehen wir zum Sanity-Dashboard. Suchen Sie im Dashboard nach dem aktuellen Projekt und navigieren Sie zu Einstellungen → API. Von hier aus können wir neue Tokens erstellen, die wir in unserem Projekt verwenden können. In vielen Projekten reicht es aus, einen Nur-Lese-Token zu erstellen. In unserem Projekt werden wir Daten zurück an Sanity senden, daher müssen wir einen Lese+Schreib-Token erstellen.

Showing a modal open in the Sanity dashboard with a Add New Token heading, a text field to set the token label with a value of Comment Engine, and three radio buttons that set if the token as read, write or deploy studio access where the write option is selected.
Hinzufügen eines neuen Lese- und Schreib-Tokens im Sanity-Dashboard

Wenn wir auf „Neuen Token hinzufügen“ klicken, erhalten wir ein Pop-up mit dem Token-Wert. Sobald es geschlossen ist, können wir den Token nicht mehr abrufen, also greifen Sie ihn sich unbedingt!

Diese Zeichenkette kommt in unsere Datei .env.local als Wert für SANITY_API_TOKEN. Da wir bereits bei manage.sanity.io angemeldet sind, können wir auch die Projekt-ID von der Spitze der Projektseite abrufen und sie als Wert für NEXT_PUBLIC_SANITY_PROJECT_ID einfügen. Der SANITY_PREVIEW_SECRET ist wichtig, wenn wir Next.js im „Vorschau-Modus“ ausführen möchten, aber für diese Demo müssen wir ihn nicht ausfüllen.

Wir sind fast bereit, unser Next-Frontend auszuführen. Solange wir noch unser Sanity-Dashboard geöffnet haben, müssen wir eine weitere Änderung in unserer Ansicht Einstellungen → API vornehmen. Wir müssen unserem lokalen Next.js-Server erlauben, Anfragen zu stellen.

In den CORS-Ursprüngen fügen wir einen neuen Ursprung hinzu und füllen ihn mit dem aktuellen lokalen Port aus: https://:3000. Wir müssen keine authentifizierten Anfragen senden können, daher können wir dies deaktiviert lassen. Wenn dies live geht, müssen wir einen zusätzlichen Ursprung mit der Produktions-URL hinzufügen, um auch der Live-Site das Stellen von Anfragen zu ermöglichen.

Unser Blog ist jetzt bereit, lokal ausgeführt zu werden!

# From inside /blog-frontend
npm run dev

Nachdem wir den obigen Befehl ausgeführt haben, haben wir nun einen Blog, der auf unserem Computer läuft und Daten von der Sanity-API abruft. Wir können https://:3000 besuchen, um die Seite anzuzeigen.

Erstellen des Schemas für Kommentare

Um Kommentare zu unserer Datenbank hinzuzufügen und sie in unserem Studio anzuzeigen, müssen wir unser Schema für die Daten einrichten.

Um unser Schema hinzuzufügen, fügen wir in unserem Verzeichnis /studio/schemas eine neue Datei namens comment.js hinzu. Diese JavaScript-Datei exportiert ein Objekt, das die Definition der gesamten Datenstruktur enthält. Dies sagt dem Studio, wie die Daten angezeigt werden sollen, und strukturiert die Daten, die wir an unser Frontend zurückgeben werden.

Im Fall eines Kommentars wollen wir das, was als „Standard“ in der Welt der Kommentare gelten könnte. Wir haben ein Feld für den Namen eines Benutzers, seine E-Mail-Adresse und einen Textbereich für eine Kommentarzeichenfolge. Neben diesen Grundlagen benötigen wir auch eine Möglichkeit, den Kommentar an einen bestimmten Beitrag zu binden. In Sanitys API ist der Feldtyp eine „Referenz“ auf einen anderen Datentyp.

Wenn wir möchten, dass unsere Seite Spam erhält, könnten wir dort aufhören, aber es wäre wahrscheinlich eine gute Idee, einen Genehmigungsprozess hinzuzufügen. Dies können wir tun, indem wir unserem Kommentar ein boolesches Feld hinzufügen, das steuert, ob ein Kommentar auf unserer Website angezeigt werden soll oder nicht.

export default {
  name: 'comment',
  type: 'document',
  title: 'Comment',
  fields: [
    {
      name: 'name',
      type: 'string',
    },
    {
      title: 'Approved',
      name: 'approved',
      type: 'boolean',
      description: "Comments won't show on the site without approval"
    },   
    {
      name: 'email',
      type: 'string',
    },
    {
      name: 'comment',
      type: 'text',
    },
    {
      name: 'post',
      type: 'reference',
      to: [
        {type: 'post'}
      ]
    }
  ],
}

Nachdem wir dieses Dokument hinzugefügt haben, müssen wir es auch zu unserer Datei /studio/schemas/schema.js hinzufügen, um es als neuen Dokumenttyp zu registrieren.

import createSchema from 'part:@sanity/base/schema-creator'
import schemaTypes from 'all:part:@sanity/base/schema-type'
import blockContent from './blockContent'
import category from './category'
import post from './post'
import author from './author'
import comment from './comment' // <- Import our new Schema
export default createSchema({
  name: 'default',
  types: schemaTypes.concat([
    post,
    author,
    category,
    comment, // <- Use our new Schema
    blockContent
  ])
})

Sobald diese Änderungen vorgenommen wurden, sehen wir, wenn wir unser Studio erneut aufrufen, einen Kommentarbereich in unserer Hauptinhaltsliste. Wir können sogar hineingehen und unseren ersten Kommentar zu Testzwecken hinzufügen (da wir noch keine Benutzeroberfläche dafür im Frontend erstellt haben).

Ein aufmerksamer Entwickler wird feststellen, dass die Vorschau unserer Kommentarliste nach dem Hinzufügen des Kommentars nicht sehr hilfreich ist. Jetzt, wo wir Daten haben, können wir eine benutzerdefinierte Vorschau für diese Listenansicht bereitstellen.

Hinzufügen einer CMS-Vorschau für Kommentare in der Listenansicht

Nach dem Array fields können wir ein Objekt preview angeben. Das Objekt preview teilt Sanitys Listenansichten mit, welche Daten und in welcher Konfiguration angezeigt werden sollen. Wir fügen dieser Objekt ein Property und eine Methode hinzu. Das Property select ist ein Objekt, das wir verwenden können, um Daten aus unserem Schema zu sammeln. In diesem Fall nehmen wir die Werte name, comment und post.title des Kommentars. Wir übergeben diese neuen Variablen in unsere Methode prepare() und verwenden diese, um einen title und subtitle für die Verwendung in Listenansichten zurückzugeben.

export default {
  // ... Fields information
  preview: {
      select: {
        name: 'name',
        comment: 'comment',
        post: 'post.title'
      },
      prepare({name, comment, post}) {
        return {
          title: `${name} on ${post}`,
          subtitle: comment
        }
      }
    }
  }

}

Der Titel wird groß und der Untertitel kleiner und blasser angezeigt. In dieser Vorschau machen wir den Titel zu einer Zeichenfolge, die den Namen des Kommentarautors und den Beitrag des Kommentars enthält, mit einem Untertitel, der den Kommentartext selbst enthält. Sie können die Vorschauen konfigurieren, um Ihren Anforderungen zu entsprechen.

Die Daten existieren jetzt, und unsere CMS-Vorschau ist bereit, aber sie werden noch nicht auf unsere Website übertragen. Wir müssen unseren Datenabruf ändern, um unsere Kommentare für jeden Beitrag zu laden.

Anzeigen der Kommentare jedes Beitrags

In diesem Repository gibt es eine Datei, die Funktionen zum Interagieren mit Sanitys API gewidmet ist. Die Datei /blog-frontend/lib/api.js enthält spezifisch exportierte Funktionen für die Anwendungsfälle verschiedener Routen auf unserer Website. Wir müssen die Funktion getPostAndMorePosts in dieser Datei aktualisieren, die die Daten für jeden Beitrag abruft. Sie gibt die entsprechenden Daten für Beiträge zurück, die dem Slug der aktuellen Seite zugeordnet sind, sowie eine Auswahl neuer Beiträge, die daneben angezeigt werden sollen.

In dieser Funktion gibt es zwei Abfragen: eine zum Abrufen der Daten für den aktuellen Beitrag und eine für die zusätzlichen Beiträge. Die zu ändernde Anfrage ist die erste Anfrage.

Ändern der zurückgegebenen Daten mit einer GROQ-Projektion

Die Abfrage erfolgt in der Open-Source-Graph-basierten Abfragesprache GROQ, die von Sanity verwendet wird, um Daten aus dem Datenspeicher abzurufen. Die Abfrage besteht aus drei Teilen

  • Der Filter – welcher Datensatz gefunden und zurückgegeben werden soll *[_type == "post" && slug.current == $slug]
  • Eine optionale Pipeline-Komponente – eine Modifikation der Daten, die von der Komponente links davon zurückgegeben werden | order(_updatedAt desc)
  • Eine optionale Projektion – die spezifischen Datenelemente, die für die Abfrage zurückgegeben werden sollen. In unserem Fall alles zwischen den Klammern ({}).

In diesem Beispiel haben wir eine variable Liste von Feldern, die die meisten unserer Abfragen benötigen, sowie die body-Daten für den Blogbeitrag. Direkt nach dem body möchten wir alle Kommentare abrufen, die mit diesem Beitrag verknüpft sind.

Um dies zu tun, erstellen wir ein benanntes Property im zurückgegebenen Objekt namens 'comments' und führen dann eine neue Abfrage aus, um die Kommentare zurückzugeben, die die Referenz auf den aktuellen Beitrags-Kontext enthalten.

Der gesamte Filter sieht so aus

*[_type == "comment" && post._ref == ^._id && approved == true]

Der Filter stimmt mit allen Dokumenten überein, die die inneren Kriterien der eckigen Klammern ([]) erfüllen. In diesem Fall finden wir alle Dokumente vom Typ _type == "comment". Wir prüfen dann, ob die _ref des aktuellen Beitrags mit der _id des Kommentars übereinstimmt. Schließlich prüfen wir, ob der Kommentar approved == true ist.

Sobald wir diese Daten haben, wählen wir die gewünschten Daten mit einer optionalen Projektion aus. Ohne die Projektion würden wir alle Daten für jeden Kommentar erhalten. In diesem Beispiel nicht wichtig, aber eine gute Gewohnheit.

curClient.fetch(
    `*[_type == "post" && slug.current == $slug] | order(_updatedAt desc) {
        ${postFields}
        body,
        'comments': *[_type == "comment" && post._ref == ^._id && approved == true]{
            _id, 
            name, 
            email, 
            comment, 
            _createdAt
        }
    }`,
 { slug }
 )
 .then((res) => res?.[0]),

Sanity gibt ein Array von Daten in der Antwort zurück. Dies kann in vielen Fällen hilfreich sein, aber für uns benötigen wir nur das erste Element im Array, daher beschränken wir die Antwort auf nur den Index null.

Hinzufügen einer Kommentar-Komponente zu unserem Beitrag

Unsere einzelnen Beiträge werden mit Code aus der Datei /blog-frontend/pages/posts/[slug].js gerendert. Die Komponenten in dieser Datei empfangen bereits die aktualisierten Daten aus unserer API-Datei. Die Hauptfunktion Post() gibt unser Layout zurück. Hier fügen wir unsere neue Komponente hinzu.

Kommentare erscheinen normalerweise nach dem Inhalt des Beitrags, also fügen wir diese unmittelbar nach dem schließenden Tag </article> ein.

// ... The rest of the component
</article>
// The comments list component with comments being passed in
<Comments comments={post?.comments} />

Wir müssen jetzt unsere Komponentendatei erstellen. Die Komponentendateien in diesem Projekt befinden sich im Verzeichnis /blog-frontend/components. Wir folgen dem Standardmuster für die Komponenten. Die Hauptfunktionalität dieser Komponente besteht darin, das übergebene Array zu nehmen und eine unsortierte Liste mit korrektem Markup zu erstellen.

Da wir bereits eine Komponente <Date /> haben, können wir diese verwenden, um unser Datum richtig zu formatieren.

# /blog-frontend/components/comments.js

import Date from './date'

export default function Comments({ comments = [] }) {
  return (
    <>
     <h2 className="mt-10 mb-4 text-4xl lg:text-6xl leading-tight">Comments:</h2>
      <ul>
        {comments?.map(({ _id, _createdAt, name, email, comment }) => (
          <li key={_id} className="mb-5">
            <hr className="mb-5" />
            <h4 className="mb-2 leading-tight"><a href={`mailto:${email}`}>{name}</a> (<Date dateString={_createdAt}/>)</h4>
            <p>{comment}</p>
            <hr className="mt-5 mb-5" />
         </li>
        ))
      </ul>
    </>
  )
}

Zurück in unserer Datei /blog-frontend/pages/posts/[slug].js müssen wir diese Komponente oben importieren, und dann haben wir einen Kommentarbereich für Beiträge mit Kommentaren.

import Comments from '../../components/comments'

Wir haben jetzt unseren manuell eingegebenen Kommentar aufgelistet. Das ist großartig, aber nicht sehr interaktiv. Fügen wir dem Formular ein Formular hinzu, damit Benutzer einen Kommentar in unserem Datensatz einreichen können.

Hinzufügen eines Kommentarformulars zu einem Blogbeitrag

Für unser Kommentarformular, warum das Rad neu erfinden? Wir sind bereits im React-Ökosystem mit Next.js, also nutzen wir es auch gleich. Wir werden das Paket `react-hook-form` verwenden, aber jedes Formular oder jede Formular-Komponente ist in Ordnung.

Zuerst müssen wir unser Paket installieren.

npm install react-hook-form

Während das installiert wird, können wir unser Formular-Komponente einrichten. In der Beitrags-Komponente können wir eine <Form /> Komponente direkt nach unserer neuen <Comments /> Komponente hinzufügen.

// ... Rest of the component
<Comments comments={post.comments} />
<Form _id={post._id} />

Beachten Sie, dass wir die aktuelle Beitrags-_id an unsere neue Komponente übergeben. So binden wir unseren Kommentar an unseren Beitrag.

Wie wir es mit unserer Kommentar-Komponente getan haben, müssen wir eine Datei für diese Komponente unter /blog-frontend/components/form.js erstellen.

export default function Form ({_id}) {

  // Sets up basic data state
  const [formData, setFormData] = useState() 
        
  // Sets up our form states 
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [hasSubmitted, setHasSubmitted] = useState(false)
        
  // Prepares the functions from react-hook-form
  const { register, handleSubmit, watch, errors } = useForm()

  // Function for handling the form submission
  const onSubmit = async data => {
    // ... Submit handler
  }

  if (isSubmitting) {
    // Returns a "Submitting comment" state if being processed
    return <h3>Submitting comment…</h3>
  }
  if (hasSubmitted) {
    // Returns the data that the user submitted for them to preview after submission
    return (
      <>
        <h3>Thanks for your comment!</h3>
        <ul>
          <li>
            Name: {formData.name} <br />
            Email: {formData.email} <br />
            Comment: {formData.comment}
          </li>
        </ul>
      </>
    )
  }

  return (
    // Sets up the Form markup
  )
}

Dieser Code ist hauptsächlich Boilerplate, um die verschiedenen Zustände des Formulars zu behandeln. Das Formular selbst ist das Markup, das wir zurückgeben.

// Sets up the Form markup
<form onSubmit={handleSubmit(onSubmit)} className="w-full max-w-lg" disabled>
  <input ref={register} type="hidden" name="_id" value={_id} />
									
  <label className="block mb-5">
    <span className="text-gray-700">Name</span>
    <input name="name" ref={register({required: true})} className="form-input mt-1 block w-full" placeholder="John Appleseed"/>
    </label>
																																																									
  <label className="block mb-5">
    <span className="text-gray-700">Email</span>
    <input name="email" type="email" ref={register({required: true})} className="form-input mt-1 block w-full" placeholder="[email protected]"/>
  </label>

  <label className="block mb-5">
    <span className="text-gray-700">Comment</span>
    <textarea ref={register({required: true})} name="comment" className="form-textarea mt-1 block w-full" rows="8" placeholder="Enter some long form content."></textarea>
  </label>
																																					
  {/* errors will return when field validation fails  */}
  {errors.exampleRequired && <span>This field is required</span>}
	
  <input type="submit" className="shadow bg-purple-500 hover:bg-purple-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded" />
</form>

In diesem Markup haben wir ein paar Sonderfälle. Erstens hat unser <form>-Element ein onSubmit-Attribut, das den handleSubmit()-Hook akzeptiert. Dieser Hook, der von unserem Paket bereitgestellt wird, nimmt den Namen der Funktion entgegen, die die Einreichung unseres Formulars verarbeitet.

Das allererste Eingabefeld in unserem Kommentarformular ist ein verstecktes Feld, das die _id unseres Beitrags enthält. Jedes erforderliche Formularfeld verwendet das ref-Attribut, um sich bei der Validierung von `react-hook-form` zu registrieren. Wenn unser Formular abgeschickt wird, müssen wir etwas mit den eingereichten Daten tun. Dafür ist unsere onSubmit()-Funktion da.

// Function for handling the form submission
const onSubmit = async data => {
  setIsSubmitting(true)
        
  setFormData(data)
        
  try {
    await fetch('/api/createComment', {
      method: 'POST',
     body: JSON.stringify(data),
     type: 'application/json'
    })  
    setIsSubmitting(false)
    setHasSubmitted(true)
  } catch (err) {
    setFormData(err)
  }
}

Diese Funktion hat zwei Hauptziele

  1. Setzen des Zustands für das Formular durch den Einreichungsprozess mit dem zuvor erstellten Zustand
  2. Senden der Daten an eine serverlose Funktion über eine fetch()-Anfrage. Next.js verfügt über integriertes fetch(), sodass wir kein zusätzliches Paket installieren müssen.

Wir können die vom Formular übermittelten Daten – das data-Argument für unseren Formularhandler – an eine serverlose Funktion übermitteln, die wir erstellen müssen.

Wir könnten dies direkt an die Sanity-API senden, aber das erfordert einen API-Schlüssel mit Schreibzugriff und Sie sollten diesen mit Umgebungsvariablen außerhalb Ihres Frontends schützen. Eine serverlose Funktion ermöglicht es Ihnen, diese Logik auszuführen, ohne das geheime Token gegenüber Ihren Besuchern preiszugeben.

Kommentar mit einer Next.js API-Route an Sanity senden

Um unsere Anmeldedaten zu schützen, schreiben wir unseren Formularhandler als serverlose Funktion. In Next.js können wir „API-Routen“ verwenden, um serverlose Funktionen zu erstellen. Diese befinden sich zusammen mit unseren Seitenrouten im Verzeichnis /blog-frontent/pages im Verzeichnis api. Wir können hier eine neue Datei namens createComment.js erstellen.

Um an die Sanity-API zu schreiben, müssen wir zuerst einen Client einrichten, der Schreibberechtigungen hat. Früher in dieser Demo haben wir einen Lese+Schreib-Token eingerichtet und ihn in /blog-frontent/.env.local abgelegt. Diese Umgebungsvariable wird bereits in einem Client-Objekt aus /blog-frontend/lib/sanity.js verwendet. Es gibt einen Lese+Schreib-Client namens previewClient, der den Token verwendet, um unveröffentlichte Änderungen für den Vorschau-Modus abzurufen.

Am Anfang unserer Datei createClient können wir dieses Objekt für die Verwendung in unserer serverlosen Funktion importieren. Eine Next.js-API-Route muss ihren Handler als Standardfunktion mit Anforderungs- und Antwortargumenten exportieren. Innerhalb unserer Funktion dekonstruieren wir unsere Formulardaten aus dem Body des Request-Objekts und verwenden diese, um ein neues Dokument zu erstellen.

Sanitys JavaScript-Client hat eine Methode create(), die ein Datenobjekt akzeptiert. Das Datenobjekt sollte einen _type enthalten, der dem Typ des zu erstellenden Dokuments entspricht, sowie alle Daten, die wir speichern möchten. In unserem Beispiel übergeben wir ihm den Namen, die E-Mail-Adresse und den Kommentar.

Wir müssen ein wenig zusätzliche Arbeit leisten, um die _id unseres Beitrags in eine Referenz auf den Beitrag in Sanity umzuwandeln. Wir definieren das Property post als eine Referenz und geben die _id als _ref-Property dieses Objekts an. Nachdem wir es an die API gesendet haben, können wir je nach Antwort von Sanity entweder einen Erfolgs- oder einen Fehlerstatus zurückgeben.

// This Next.js template already is configured to write with this Sanity Client
import {previewClient} from '../../lib/sanity'

export default async function createComment(req, res) {
  // Destructure the pieces of our request
  const { _id, name, email, comment} = JSON.parse(req.body)
  try {
    // Use our Client to create a new document in Sanity with an object  
    await previewClient.create({
      _type: 'comment',
      post: {
        _type: 'reference',
        _ref: _id,
      },
     name,
     email,
     comment
    })
  } catch (err) {
    console.error(err)
    return res.status(500).json({message: `Couldn't submit comment`, err})
  }
    
  return res.status(200).json({ message: 'Comment submitted' })
}

Sobald diese serverlose Funktion eingerichtet ist, können wir zu unserem Blogbeitrag navigieren und einen Kommentar über das Formular einreichen. Da wir einen Genehmigungsprozess haben, können wir nach dem Einreichen eines Kommentars diesen im Sanity Studio anzeigen und entscheiden, ob wir ihn genehmigen, ablehnen oder als ausstehend belassen.

Die Kommentar-Engine weiter ausbauen

Dies verschafft uns die grundlegende Funktionalität eines Kommentarsystems, das direkt mit unseren Inhalten verbunden ist. Es gibt viel Potenzial, wenn Sie beide Seiten dieses Flows kontrollieren. Hier sind ein paar Ideen, wie Sie diese Kommentar-Engine weiter ausbauen können.

  • Erstellen und senden Sie eine E-Mail-Benachrichtigung für eine neue Nachricht mit SendGrid oder anderen Maildiensten.
  • Teilen Sie die Sanity Studio API, um genehmigte, nicht genehmigte und ausstehende Kommentare anzuzeigen, mit Sanitys Structure Builder.
  • Implementieren Sie Spam-Schutz mit Googles unsichtbarem reCAPTCHA.
  • Integrieren Sie mit Gravatar, wenn ein Kommentar gespeichert wird.