Nu het gebruik van chatbots en virtuele assistenten blijft groeien, zijn veel bedrijven en developers op zoek naar manieren om hun eigen AI aangedreven chatbots te maken. ChatGPT is zo’n chatbot, gemaakt door OpenAI, die in staat is om mensachtige gesprekken te voeren en een breed scala aan vragen te beantwoorden.

Wat je gaat bouwen

In deze tutorial leer je hoe je een ChatGPT kloonapplicatie bouwt met React en de OpenAI API. Als je in het weekend een leuk en boeiend project wilt proberen, dan is dit een mooie gelegenheid om in React en OpenAI te duiken.

Je leert ook hoe je direct vanuit je GitHub repository kunt deployen naar Kinsta’s Applicatie Hosting platform, dat een gratis .kinsta.app domein biedt om je project snel live te laten gaan. En met Kinsta’s gratis trial en Hobby pakket kun je gemakkelijk en zonder kosten aan de slag.

Hier is een live demo van de ChatGPT kloonapplicatie.

ChatGPT kloonapplicatie
ChatGPT kloonapplicatie

Als je dit project nader wilt bekijken, kun je de GitHub repository ervan openen.

Als alternatief kun je met dit starterproject template kiezen voor Use this template > Create a new repository – dit kopieert de starter code naar een nieuwe repository. Dit starterproject bevat fundamentele elementen zoals stijlen, Font Awesome CDN link, OpenAi pakket, en een basisstructuur om je te helpen aan de slag te gaan.

 

Vereisten

Deze tutorial is ontworpen als een “follow-along”. Daarom wordt aanbevolen dat je over het volgende beschikt om gemakkelijk mee te kunnen coderen:

Wat is OpenAI API?

De OpenAI API is een cloud-gebaseerd platform dat developers via een API toegang geeft tot de taalmodellen van OpenAI, zoals GPT-3. Hiermee kunnen developers features voor natuurlijke taalverwerking zoals tekstaanvulling, sentimentanalyse, samenvatting en vertaling toevoegen aan hun applicaties zonder hun eigen modellen te hoeven ontwikkelen en te trainen.

Om de OpenAI API te gebruiken moeten developers  een account aanmaken op de OpenAI website en een API sleutel aanvragen. De API-sleutel wordt gebruikt om API verzoeken te authentiseren en het gebruik bij te houden.

Zodra de API sleutel is verkregen, kunnen developers  de API gebruiken om tekst aan het taalmodel voor te leggen en antwoorden te ontvangen.

Waarom React?

React is een populaire JavaScript bibliotheek voor het bouwen van gebruikersinterfaces. Volgens het Stack Overflow developersonderzoek van 2022 is het de op één na meest gebruikte webtechnologie, met 42,62% van het marktaandeel.

Met React kunnen developers declaratieve componenten maken die verschillende onderdelen van de gebruikersinterface vertegenwoordigen. Deze componenten worden gedefinieerd met een syntaxis genaamd JSX, wat een combinatie is van JavaScript en HTML.

Dankzij het grote ecosysteem van componentbibliotheken en kits kunnen developers gemakkelijk werken met en integreren van API’s, zoals de OpenAI API, om complexe chatinterfaces te bouwen, en dat maakt het een uitstekende keuze voor het bouwen van een ChatGPT kloonapplicatie.

Zo stel je je React ontwikkelomgeving in

De beste manier om React te installeren of een React project te maken is door het te installeren met create-react-app. Een eerste vereiste is dat Node.js op je machine is geïnstalleerd. Om te bevestigen dat je Node geïnstalleerd hebt, voer je het volgende commando uit in je terminal.

node -v

Als er een versie verschijnt, dan bestaat die. Om npx te gebruiken, moet je ervoor zorgen dat je Node versie niet minder is dan v14.0.0, en je NPM versie niet minder is dan v5.6; anders zou je die moeten bijwerken door npm update -g uit te voeren. Als je npm hebt uitgezocht, kun je nu een React project opzetten door het onderstaande commando uit te voeren:

npx create-react-app chatgpt-clone

Opmerking: “chatgpt-clone” is de applicatienaam die we maken, maar je kunt hem veranderen in een naam naar keuze.

Het installatieproces kan enkele minuten duren. Eenmaal succesvol, kun je naar de map navigeren en het Node.js OpenAI pakket installeren, dat gemakkelijke toegang biedt tot de OpenAI API vanuit Node.js met het onderstaande commando:

npm install openai

Je kunt nu npm start uitvoeren om je applicatie live te zien op localhost:3000.

Wanneer een React project wordt gemaakt met het commando create-react-app, wordt automatisch een mappenstructuur geschetst. De belangrijkste map die je aangaat is de map src, waar de ontwikkeling plaatsvindt. Deze map bevat standaard veel bestanden, maar je zou je alleen bezig moeten houden met de bestanden App.js, index.js en index.css.

  1. App.js: Het App.js bestand is de belangrijkste component in een React applicatie. Het vertegenwoordigt typisch het top-level component dat alle andere componenten in de applicatie rendert.
  2. index.js: Dit bestand is het ingangspunt van je React applicatie. Het is het eerste bestand dat wordt geladen als de app wordt geopend en is verantwoordelijk voor het renderen van de App.js component naar de browser.
  3. index.css: Dit bestand is verantwoordelijk voor het definiëren van de algemene styling en opmaak van je React applicatie.

Zo bouw je een ChatGPT kloon met React en OpenAI API

De ChatGPT kloonapplicatie zal bestaan uit twee componenten om de applicatie gemakkelijker te begrijpen en te onderhouden. Deze twee componenten zijn:

  1. Form Section: Deze component bevat een tekstveld en een knop voor gebruikers om te communiceren met de chatbot.
  2. Answer Section: De vragen en bijbehorende antwoorden worden opgeslagen in een array en weergegeven in deze sectie. Je doorloopt de matrix chronologisch, waarbij de nieuwste eerst wordt getoond.

De ChatGPT kloonapplicatie instellen

In deze tutorial beginnen we met het bouwen van de applicatie interface en daarna kun je de functionaliteit implementeren zodat je applicatie interageert met de OpenAI API. Begin met het maken van de twee componenten die je in deze tutorial zult gebruiken. Voor een goede organisatie maak je een components map in de src map waar alle componenten worden opgeslagen.

Het Form Section component

Dit is een eenvoudig formulier dat bestaat uit een textarea en een submit button.

// components/FormSection.jsx

const FormSection = () => {

    return (
        <div className="form-section">
            <textarea
                rows="5"
                className="form-control"
                placeholder="Ask me anything..."
            ></textarea>
            <button className="btn">
                Generate Response 🤖
            </button>
        </div>
    )
}

export default FormSection;

Zo zal het formulier er naar verwachting uitzien als je het importeert in je App.js bestand:

Form section component voor ChatGPT kloon
Form section component

Het Answer Section component

In deze sectie worden alle vragen en antwoorden getoond. Zo ziet deze sectie eruit als je hem ook importeert in je App.js bestand.

Answer section component van de ChatGPT kloon
Answer section component

Je haalt deze vragen en antwoorden op uit een array en een loop om je code gemakkelijker leesbaar en onderhoudbaar te maken.

// components/AnswerSection.jsx

const AnswerSection = () => {
    return (
        <>
            <hr className="hr-line" />
            <div className="answer-container">
                <div className="answer-section">
                    <p className="question">Who is the founder of OpenAi?</p>
                    <p className="answer">OpenAI was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, Wojciech Zaremba, and John Schulman.</p>
                    <div className="copy-icon">
                        <i className="fa-solid fa-copy"></i>
                    </div>
                </div>
            </div>
        </>
    )
}

export default AnswerSection;

De startpagina

Je hebt nu beide componenten gemaakt, maar er zal niets verschijnen als je je applicatie uitvoert, omdat je ze moet importeren in je App.js bestand. Voor deze applicatie zul je geen enkele vorm van routing implementeren, wat betekent dat het App.js bestand zal dienen als de thuiscomponent/pagina van je applicatie.

Je kunt wat content toevoegen, zoals de titel en beschrijving van je applicatie, voordat je de componenten importeert.

// App.js

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    return (
        <div>
            <div className="header-section">
                <h1>ChatGPT CLONE 🤖</h1>
                <p>
                    I am an automated question and answer system, designed to assist you
                    in finding relevant information. You are welcome to ask me any queries
                    you may have, and I will do my utmost to offer you a reliable
                    response. Kindly keep in mind that I am a machine and operate solely
                    based on programmed algorithms.
                </p>
            </div>

            <FormSection />
            <AnswerSection />
        </div>
    );
};

export default App;

In bovenstaande code worden de twee componenten geïmporteerd en toegevoegd aan de applicatie. Als je je applicatie uitvoert, ziet je applicatie er zo uit:

Complete ChatGPT kloonapplicatie
Complete ChatGPT kloonapplicatie

Functionaliteit toevoegen en OpenAI API integreren

Je hebt nu de gebruikersinterface van je applicatie. De volgende stap is om de applicatie functioneel te maken, zodat hij kan communiceren met de OpenAI API en antwoorden kan krijgen. Eerst moet je de waarde van je formulier krijgen als het wordt ingediend, want die zal worden gebruikt om de OpenAI API te bevragen.

Gegevens uit een formulier halen

In React is de beste manier om gegevens op te slaan en bij te werken het gebruik van states. In functionele componenten wordt de useState() hook gebruikt om met states te werken. Je kunt een state aanmaken, de waarde van je formulier aan de state toewijzen, en deze bijwerken wanneer de waarde verandert. Laten we beginnen met het importeren van de useState() hook in de component FormSection.jsx en dan een state maken om op te slaan en bij te werken newQuestions.

// components/FormSection.jsx

import { useState } from 'react';

const FormSection = ({ generateResponse }) => {
    const [newQuestion, setNewQuestion] = useState('');

    return (
        // Form to submit a new question
    )
}

export default FormSection;

Vervolgens kun je de waarde van het veld textarea toewijzen aan de state en een event onChange() maken om de state bij te werken telkens als de invoerwaarde verandert:

<textarea
    rows="5"
    className="form-control"
    placeholder="Ask me anything..."
    value={newQuestion}
    onChange={(e) => setNewQuestion(e.target.value)}
></textarea>

Tenslotte kun je een onClick() event aanmaken, om een functie te laden telkens wanneer op de verzendknop wordt geklikt. Deze methode wordt aangemaakt in het App.js bestand en als een props doorgegeven aan het FormSection.jsx component met de newQuestion en setNewQuestion waarden als argumenten.

<button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
    Generate Response 🤖
</button>

Je hebt nu een state gecreëerd om de waarde van het formulier op te slaan en bij te werken, een methode toegevoegd die als props wordt doorgegeven vanuit het App.js bestand en het click event afgehandeld. Zo ziet de uiteindelijke code eruit:

// components/FormSection.jsx

import { useState } from 'react';

const FormSection = ({ generateResponse }) => {
    const [newQuestion, setNewQuestion] = useState('');

    return (
        <div className="form-section">
            <textarea
                rows="5"
                className="form-control"
                placeholder="Ask me anything..."
                value={newQuestion}
                onChange={(e) => setNewQuestion(e.target.value)}
            ></textarea>
            <button className="btn" onClick={() => generateResponse(newQuestion, setNewQuestion)}>
                Generate Response 🤖
            </button>
        </div>
    )
}

export default FormSection;

De volgende stap is het maken van een methode in het App.js bestand om het hele proces van interactie met OpenAI API af te handelen.

Interactie met OpenAI API

Voor interactie met OpenAI API en het verkrijgen van API sleutels in een React applicatie moet je een OpenAI API account aanmaken. Je kunt je aanmelden voor een account op de OpenAI website met behulp van je google account of e-mail. Om een API sleutel te genereren, klik je op Personal in de rechterbovenhoek van de website; er verschijnen enkele opties; klik op View API keys.

Toegang tot OpenAI API sleutels.
Toegang tot OpenAI API sleutels.

Klik op de knop Create new secret key, kopieer de sleutel ergens zoals je die in deze applicatie zou gebruiken voor interactie met OpenAI. Je kunt nu doorgaan met het initialiseren van OpenAI door het OpenAI pakket (dat je al geïnstalleerd hebt) te importeren, samen met de configuratiemethode. Maak dan een configuratie met je gegenereerde sleutel en gebruik die om OpenAI te initialiseren.

// src/App.js

import { Configuration, OpenAIApi } from 'openai';

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    return (
        // Render FormSection and AnswerSection
    );
};

export default App;

In de bovenstaande code wordt de OpenAI API sleutel opgeslagen als omgevingsvariabele in het .env bestand. Je kunt een .env bestand aanmaken in de hoofdmap van je applicatie en de sleutel opslaan in de variabele REACT_APP_OPENAI_API_KEY.

// .env
REACT_APP_OPENAI_API_KEY = sk-xxxxxxxxxx…

Je kunt nu doorgaan met het maken van de generateResponse methode in het App.js bestand, en de twee parameters doorgeven die worden verwacht van het formulier dat je al hebt gemaakt om het verzoek af te handelen en antwoord te krijgen van de API.

// src/App.js

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    const generateResponse = (newQuestion, setNewQuestion) => {
        // Set up OpenAI API and handle response
    };

    return (
        // Render FormSection and AnswerSection
    );
};

export default App;

Je kunt nu een verzoek sturen naar de OpenAI API. De OpenAI API kan veel bewerkingen uitvoeren, zoals vraag en antwoord (V&A), grammaticacorrectie, vertaling en nog veel meer. Voor elk van deze bewerkingen zijn de opties verschillend. Bijvoorbeeld, de enginewaarde voor Q&A is text-davinci-00, terwijl voor SQL vertalen code-davinci-002 is. Kijk gerust in de OpenAI voorbeelddocumentatie voor de verschillende voorbeelden en hun opties.

Voor deze tutorial werken we alleen met V&A, zo ziet de optie eruit:

{
  model: "text-davinci-003",
  prompt: "Who is Obama?",
  temperature: 0,
  max_tokens: 100,
  top_p: 1,
  frequency_penalty: 0.0,
  presence_penalty: 0.0,
  stop: [""],
}

Opmerking: Ik heb de promptwaarde veranderd.

De prompt is de vraag die vanuit het formulier wordt verzonden. Dit betekent dat je die moet ontvangen van de formulierinvoer die je als parameter doorgeeft aan de methode generateResponse. Hiervoor definieer je de opties en gebruik je vervolgens de spread operator om een complete optie te maken die de prompt bevat:

// src/App.js

import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    const generateResponse = async (newQuestion, setNewQuestion) => {
        let options = {
            model: 'text-davinci-003',
            temperature: 0,
            max_tokens: 100,
            top_p: 1,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
            stop: ['/'],
        };

        let completeOptions = {
            ...options,
            prompt: newQuestion,
        };

    };

    return (
         // Render FormSection and AnswerSection
    );
};

export default App;

Wat nu nog rest is een verzoek via de methode createCompletion naar OpenAI te sturen om een antwoord te krijgen.

// src/App.js

import { Configuration, OpenAIApi } from 'openai';
import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

import { useState } from 'react';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    const [storedValues, setStoredValues] = useState([]);

    const generateResponse = async (newQuestion, setNewQuestion) => {
        let options = {
            model: 'text-davinci-003',
            temperature: 0,
            max_tokens: 100,
            top_p: 1,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
            stop: ['/'],
        };

        let completeOptions = {
            ...options,
            prompt: newQuestion,
        };

        const response = await openai.createCompletion(completeOptions);

        console.log(response.data.choices[0].text);
    };

    return (
        // Render FormSection and AnswerSection
    );
};

export default App;

In bovenstaande code wordt de tekst van het antwoord weergegeven op je console. Voel je vrij om je applicatie te testen door een willekeurige vraag te stellen. De laatste stap zou zijn om een state te creëren die de array van vragen en antwoorden bevat en dan deze array als een prop naar de AnswerSection component te sturen. Zo ziet de uiteindelijke code van App.js eruit:

// src/App.js
import { Configuration, OpenAIApi } from 'openai';

import FormSection from './components/FormSection';
import AnswerSection from './components/AnswerSection';

import { useState } from 'react';

const App = () => {
    const configuration = new Configuration({
        apiKey: process.env.REACT_APP_OPENAI_API_KEY,
    });

    const openai = new OpenAIApi(configuration);

    const [storedValues, setStoredValues] = useState([]);

    const generateResponse = async (newQuestion, setNewQuestion) => {
        let options = {
            model: 'text-davinci-003',
            temperature: 0,
            max_tokens: 100,
            top_p: 1,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
            stop: ['/'],
        };

        let completeOptions = {
            ...options,
            prompt: newQuestion,
        };

        const response = await openai.createCompletion(completeOptions);

        if (response.data.choices) {
            setStoredValues([
                {
                    question: newQuestion,
                    answer: response.data.choices[0].text,
                },
                ...storedValues,
            ]);
            setNewQuestion('');
        }
    };

    return (
        <div>
            <div className="header-section">
                <h1>ChatGPT CLONE 🤖</h1>
                    <p>
                        I am an automated question and answer system, designed to assist you
                        in finding relevant information. You are welcome to ask me any
                        queries you may have, and I will do my utmost to offer you a
                        reliable response. Kindly keep in mind that I am a machine and
                        operate solely based on programmed algorithms.
                    </p>
            </div>

            <FormSection generateResponse={generateResponse} />

            <AnswerSection storedValues={storedValues} />
        </div>
    );
};

export default App;

Je kunt nu de AnswerSection component bewerken, zodat deze de props waarde ontvangt van App.js en de JavaScript Map() methode gebruiken om door de storedValues array te kijken:

// components/AnswerSection.jsx

const AnswerSection = ({ storedValues }) => {
    return (
        <>
            <hr className="hr-line" />
            <div className="answer-container">
                {storedValues.map((value, index) => {
                    return (
                        <div className="answer-section" key={index}>
                            <p className="question">{value.question}</p>
                            <p className="answer">{value.answer}</p>
                            <div className="copy-icon">
                                <i className="fa-solid fa-copy"></i>
                            </div>
                        </div>
                    );
                })}
            </div>
        </>
    )
}

export default AnswerSection;

Als je je applicatie uitvoert en test door vragen te stellen, zal het antwoord hieronder worden weergegeven. Maar je zult merken dat de kopieerknop niet werkt. Je zult een onClick() event moeten toevoegen aan de knop, zodat deze een methode triggert om de functionaliteit af te handelen. Je kunt de methode navigator.clipboard.writeText() gebruiken om de functionaliteit af te handelen. Zo ziet de AnswerSection component er nu uit:

// components/AnswerSection.jsx

const AnswerSection = ({ storedValues }) => {
    const copyText = (text) => {
        navigator.clipboard.writeText(text);
    };

    return (
        <>
            <hr className="hr-line" />
            <div className="answer-container">
                {storedValues.map((value, index) => {
                    return (
                        <div className="answer-section" key={index}>
                            <p className="question">{value.question}</p>
                            <p className="answer">{value.answer}</p>
                            <div
                                className="copy-icon"
                                onClick={() => copyText(value.answer)}
                            >
                                <i className="fa-solid fa-copy"></i>
                            </div>
                        </div>
                    );
                })}
            </div>
        </>
    )
}

export default AnswerSection;

Als je je applicatie uitvoert, zal je ChatGPT kloonapplicatie perfect werken. Je kunt je applicatie nu deployen om hem online te openen en te delen met vrienden.

Zo deploy je je React applicatie naar Kinsta

Het is niet genoeg om deze applicatie te bouwen en op je lokale computers te laten staan. Je zult het online willen delen, zodat anderen er toegang toe hebben. Laten we eens kijken hoe je dit doet met GitHub en Kinsta.

Je code naar GitHub pushen

Om je code naar GitHub te pushen kun je Git commando’s gebruiken, wat een betrouwbare en efficiënte manier is om wijzigingen in de code te beheren, samen te werken aan projecten, en de versiegeschiedenis bij te houden.

De eerste stap om je codes te pushen is het aanmaken van een nieuwe repository door in te loggen op je GitHub account, te klikken op de + knop in de rechterbovenhoek van het scherm, en New repository te selecteren uit het dropdownmenu.

Een nieuw repository aanmaken op GitHub
Een nieuw repository aanmaken op GitHub

Geef je repository een naam, voeg een beschrijving toe (optioneel), en kies of je het openbaar of privé wilt hebben. Klik op Create repository om het aan te maken.

Zodra je repository is aangemaakt, zorg je ervoor dat je de URL van het repository verkrijgt van de hoofdpagina van je repository, die je nodig hebt om je code naar GitHub te pushen.

Toegang tot de URL van je repository
Toegang tot de URL van je repository

Open je terminal of commandoprompt en navigeer naar de map die je project bevat. Voer de volgende commando’s één voor één uit om je code naar je GitHub repository te pushen:

git init
git add .
git commit -m "my first commit"
git remote add origin [repository URL]
git push -u origin master

git init initialiseert een lokale Git repository, git add . voegt alle bestanden in de huidige map en zijn submappen toe aan de nieuwe Git repository. git commit -m "my first commit" commit de wijzigingen aan de repository met een korte boodschap. git remote add origin [repository URL] stelt de URL van de repository in als de remote repository en git push -u origin master pusht de code naar de remote repository (origin) in de masterbranch.

Je ChatGPT kloon React applicatie deployen op Kinsta

Volg deze stappen om je repository naar Kinsta te deployen:

  1. Log in op of maak je Kinsta account aan op het MyKinsta dashboard.
  2. Klik op Applicaties in de linker zijbalk en vervolgens op Dienst toevoegen.
  3. Selecteer Applicatie in het dropdownmenu om een React applicatie te deployen naar Kinsta.
  4. Selecteer de repository die je wilt deployen in de popup die verschijnt. Als je meerdere branches hebt, kun je de branch kiezen die je wilt inzetten en de applicatie een naam geven. Kies een datacenterlocatie uit de beschikbare 25, en Kinsta zal automatisch een startcommando detecteren.
  5. Tenslotte is het niet veilig om API sleutels naar publieke hosts zoals GitHub te pushen, het is lokaal als omgevingsvariabele toegevoegd. Bij hosting kun je het ook als omgevingsvariabele toevoegen met dezelfde variabelenaam en de sleutel als waarde.
ChatGPT kloon deployen op Kinsta.
ChatGPT kloon deployen op Kinsta.

Je applicatie zal beginnen te deployen, en binnen een paar minuten wordt een link gegeven om toegang te krijgen tot de uitgezette versie van je applicatie. In dit geval is dat https://chatgpt-clone-g9q10.kinsta.app/

Note: Je kunt automatische deployment inschakelen, zodat Kinsta je applicatie opnieuw deployt telkens als je je codebase wijzigt en naar GitHub pusht.

Samenvatting

De OpenAI API kan worden gebruikt om een groot aantal potentiële applicaties te bouwen, van klantenondersteuning en persoonlijke assistenten tot vertalingen en het maken van content.

In deze tutorial heb je geleerd hoe je met React en OpenAI een ChatGPT kloonapplicatie kunt bouwen. Je kunt deze applicatie/functie integreren in andere applicaties om gebruikers mensachtige gesprekservaringen te bieden.

Er is natuurlijk meer mogelijk met de OpenAI API en hoe deze kloonapplicatie kan worden verbeterd. Je kunt bijvoorbeeld lokale opslag deployen zodat eerdere vragen en antwoorden niet verdwijnen, ook niet nadat je je browser ververst.

Met Kinsta’s gratis trial en Hobby pakket kun je gemakkelijk en zonder kosten aan de slag met onze Applicatie Hosting. Dus waarom zou je het niet eens proberen en kijken wat je kunt maken?

Deel je project en ervaringen in het comments hieronder.

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.