En juin 2019, Prisma 2 Preview a été publié. Prisma 1 a changé notre façon d'interagir avec les bases de données. Nous pourrions accéder aux bases de données par le biais de méthodes et d'objets JavaScript simples sans avoir à écrire la requête dans le langage de base de données lui-même. Prisma 1 agissait comme une abstraction devant la base de données, il était donc plus facile de créer des applications CRUD (créer, lire, mettre à jour et supprimer) .
L’architecture de Prisma 1 ressemblait à ceci:
Notez qu'il faut un serveur Prisma supplémentaire pour que le serveur final puisse accéder à la base de données. La dernière version ne nécessite pas de serveur supplémentaire. Il s’appelle The Prisma Framework (anciennement Prisma 2), qui est une réécriture complète de Prisma. Le Prisma original a été écrit en Scala, il a donc dû être exécuté via JVM et nécessitait un serveur supplémentaire. Il avait également des problèmes de mémoire.
Le framework Prisma étant écrit en rouille, l’empreinte mémoire est faible. De plus, le serveur supplémentaire requis lors de l'utilisation de Prisma 1 est désormais fourni avec le back-end, vous pouvez donc l'utiliser comme une bibliothèque.
Le framework Prisma est composé de trois outils autonomes:
- Photon : un type de base de données non sécurisée et générée automatiquement («remplacement ORM»)
- Lift : un système de migration déclaratif avec des flux de travail personnalisés
- Studio : un environnement de base de données fournissant une interface utilisateur administrative pour prendre en charge divers flux de travail de base de données .
Photon est un client de base de données de type sécurisé qui remplace les ORM traditionnels. Lift nous permet de créer des modèles de données de manière déclarative et d'effectuer des migrations de base de données. Studio nous permet d'effectuer des opérations de base de données via une superbe interface utilisateur Admin.
Pourquoi utiliser Prisma?
Prisma supprime la complexité de l'écriture de requêtes de base de données complexes et simplifie l'accès à la base de données dans l'application. En utilisant Prisma, vous pouvez modifier les bases de données sous-jacentes sans avoir à modifier chaque requête. Ça fonctionne. À l'heure actuelle, il ne prend en charge que MySQL, SQLite et PostgreSQL.
Prisma fournit un accès à la base de données conforme au type fourni par un client Prisma généré automatiquement. Il dispose d'une API simple et puissante pour travailler avec des données et des transactions relationnelles. Il permet la gestion visuelle des données avec Prisma Studio .
Assurer la sécurité de type de bout en bout signifie que les développeurs peuvent avoir confiance en leur code, grâce à l'analyse statique et au contrôle d'erreur au moment de la compilation. L'expérience du développeur augmente considérablement lorsque les types de données sont clairement définis. Les définitions de types constituent le fondement des fonctionnalités IDE, telles que l'auto-complétion intelligente ou la définition rapide.
Prisma uniformise l'accès à plusieurs bases de données à la fois (à venir) et réduit donc considérablement la complexité des flux de travail entre bases de données (à venir). .
Il fournit des migrations automatiques de base de données (facultatif) via Lift, basé sur un modèle de données déclaratif exprimé à l'aide du langage de définition de schéma (SDL) de GraphQL.
Prérequis
Pour ce tutoriel, vous devez posséder des connaissances de base de . Réagir . Vous devez également comprendre React Hooks .
Étant donné que ce didacticiel est principalement consacré à Prisma, il est supposé que vous possédez déjà une connaissance pratique de React et de ses concepts de base. avoir une connaissance pratique du contenu ci-dessus, ne vous inquiétez pas. Il existe une multitude de didacticiels disponibles qui vous prépareront à suivre ce post.
Tout au long de ce didacticiel, nous utiliserons le fil
. Si vous n'avez pas le fil
déjà installé, installez-le à partir de ici .
Pour vous assurer que nous sommes sur la même page, voici les versions utilisées dans ce tutoriel:
- Noeud v12.11.1
- npm v6.11.3
- npx v6.11.3
- fil v1.19.1
- prisma2 v2.0.0-preview016.2
- rea v16.11.0
Folder Structure
La structure de notre dossier sera la suivante:
streaks-app /
client/
serveur/
Le dossier client /
sera initialisé à partir de create-react-app tandis que le dossier serveur /
sera initialisé à partir de prisma2 CLI.
Il vous suffit donc de créer un dossier racine appelé streaks-app /
et les sous-dossiers seront générés lors de son échafaudage avec les CLI respectifs. Allez-y et créez le dossier streaks-app /
et cd
comme suit:
$ mkdir streaks-app && cd $ _
Le serveur (côté serveur)
Démarrez un nouveau projet Prisma 2
Vous pouvez amorcer un nouveau projet Prisma 2 à l'aide de la commande npx comme suit:
$ npx prisma2 serveur d'initialisation
Vous pouvez également installer prisma2
dans le monde en ligne de commande et exécuter la commande init
. Effectuez les opérations suivantes:
$ yarn global add prisma2 // ou npm install --global prisma2
$ prisma2 init server
Exécutez l'intercalaire prisma2 init
interactif
Sélectionnez l'option suivante dans les invites interactives:
- Sélectionnez Kit de démarrage
- Sélectionnez JavaScript
- Sélectionnez API GraphQL
- Sélectionnez SQLite
Une fois terminée, la commande init
aura créé une configuration initiale du projet sur le serveur . /
.
Ouvrez maintenant le fichier schema.prisma
et remplacez-le par le suivant:
générateur de photon {
provider = "photonjs"
}
source de données db {
provider = "sqlite"
url = "fichier: dev.db"
}
modèle Habit {
id String @default (cuid ()) @id
name String @unique
strie Int
}
schema.prisma
contient le modèle de données ainsi que les options de configuration.
Ici, nous spécifions que nous voulons nous connecter à la source de données SQLite appelée dev.db
en tant que ainsi que des générateurs de code cible comme le générateur photonjs
Nous définissons ensuite le modèle de données Habit
qui consiste en id
name
et streak
.
id
est une clé primaire de type String
avec la valeur par défaut de cuid () .
. nom
est du type String
mais avec la contrainte qu'il doit être unique.
la série
est du type Int
.
. 19659002] Le fichier seed.js
devrait ressembler à ceci:
const {Photon} = require ('@ généré / photon')
const photon = new Photon ()
fonction async. main () {
const workout = wait photon.habits.create ({
Les données: {
nom: 'entraînement',
série: 49,
},
})
const running = wait photon.habits.create ({
Les données: {
nom: 'Running',
série: 245,
},
})
cyclage constant = wait photon.habits.create ({
Les données: {
nom: 'cyclisme',
série: 77,
},
})
const meditation = wait photon.habits.create ({
Les données: {
nom: 'méditation',
série: 60,
},
})
console.log ({
faire des exercices,
fonctionnement,
cyclisme,
méditation,
})
}
principale()
.catch (e => console.error (e))
.finally (async () => {
attendez photon.disconnect ()
})
Ce fichier crée toutes sortes de nouvelles habitudes et les ajoute à la base de données SQLite.
Maintenant, allez dans le fichier src / index.js
et supprimez son contenu. Nous allons commencer à ajouter du contenu à partir de zéro.
Commencez par importer les paquetages nécessaires et déclarez certaines constantes:
const {GraphQLServer} = require ('graphql-yoga')
const {
makeSchema,
type d'objet,
type de requête,
type de mutation,
idArg,
stringArg,
} = require ('lien')
const {Photon} = require ('@ généré / photon')
const {nexusPrismaPlugin} = require ('nexus-prisma')
Déclarons maintenant notre modèle Habit
juste en dessous:
const Habit = objectType ({
nom: 'Habit',
définition (t) {
t.model.id ()
t.model.name ()
t.model.streak ()
},
})
Nous utilisons objectType
du paquet nexus
pour déclarer Habit
.
Le paramètre nom
doit être identique. tel que défini dans le fichier schema.prisma
.
La fonction definition
vous permet d'exposer un ensemble particulier de champs où Habit
est référencé. Ici, nous exposons id
nom
et série
.
Si nous exposons uniquement le id
et le nom
seuls ces deux objets seront exposés où l'habitude
soit référencée.
En dessous, collez la constante de la requête
:
const Query = queryType ({
définition (t) {
t.crud.habit ()
t.crud.habits ()
// t.list.field ('habitudes', {
// tapez: 'Habit',
// résoudre: (_, _args, ctx) => {
// retourne ctx.photon.habits.findMany ()
//},
//})
},
})
Nous utilisons le queryType
du paquet nexus
pour déclarer Query
.
Le générateur Photon génère une API qui expose les fonctions CRUD sur le Modèle d'habitude
. C’est ce qui nous permet d’exposer la méthode t.crud.habit ()
et t.crud.habits ()
.
t.crud.habit ()
nous permet d'interroger toute habitude par son id
ou par son nom
. t.crud.habits ()
renvoie simplement toutes les habitudes.
Sinon, t.crud.habits ()
peut également s'écrire comme suit:
t.list. champ ('habitudes', {
type: 'Habit',
résoudre: (_, _args, ctx) => {
retourne ctx.photon.habits.findMany ()
},
})
Les codes ci-dessus et t.crud.habits ()
donneront les mêmes résultats.
Dans le code ci-dessus, nous créons un champ nommé habitudes
. Le type de retour
est Habit
. Nous appelons ensuite ctx.photon.habits.findMany ()
pour obtenir toutes les habitudes de notre base de données SQLite.
Notez que le nom de la propriété habitudes
est auto. -généré à l'aide du paquet pluralize . Il est donc recommandé de nommer nos modèles singulier – c'est-à-dire Habit
et non pas Habits
.
Nous utilisons la méthode findMany
sur . ] habitudes
qui renvoie une liste d'objets. Nous trouvons toutes les habitudes
comme nous n'avons mentionné aucune condition à l'intérieur de findMany
. Pour en savoir plus sur l'ajout de conditions à l'intérieur de trouvez beaucoup de
ici .
Au-dessous de Requête
coller Mutation
comme suit:
const Mutation = type de mutation ({
définition (t) {
t.crud.createOneHabit ({alias: 'createHabit'})
t.crud.deleteOneHabit ({alias: 'deleteHabit'})
t.field ('incrementStreak', {
type: 'Habit',
args: {
nom: stringArg (),
},
résoudre: async (_, {name}, ctx) => {
const habit = wait ctx.photon.habits.findOne ({
où: {
prénom,
},
})
retourne ctx.photon.habits.update ({
Les données: {
série: habit.streak + 1,
},
où: {
prénom,
},
})
},
})
},
})
Mutation
utilise mutationType
du paquet nexus
.
L'API de CRUD expose ici createOneHabit
et .
.
createOneHabit
comme son nom l'indique, crée une habitude alors que deleteOneHabit
supprime une habitude.
createOneHabit
est également aliasé. createHabit donc tout en appelant la mutation, nous appelons createHabit
plutôt que createOneHabit
.
De la même façon, nous appelons deleteHabit
au lieu de deleteOneHabit
.
Enfin, nous créons un champ nommé incrementStreak
qui incrémente la strie d’une habitude. Le type de retour
est Habit
. Il faut un argument nommé
comme spécifié dans le champ args
de type String
. Cet argument est reçu dans la fonction de résolution
en tant que deuxième argument. On trouve l'habitude
en appelant ctx.photon.habits.findOne ()
en passant dans le paramètre name
de la clause où
où. Nous en avons besoin pour obtenir notre série actuelle
. Enfin, nous mettons à jour l'habitude
en incrémentant la série
de 1.
Au-dessous de Mutation
collez ce qui suit:
const photon = new Photon ( )
nouveau GraphQLServer ({
schéma: makeSchema ({
types: [Query, Mutation, Habit],
plugins: [nexusPrismaPlugin()],
}),
contexte: {photon},
}). start (() =>
console.log (
`? Serveur prêt à l'adresse: http: // localhost: 4000 n⭐️ Voir des exemples de requêtes: http: // pris.ly / e / js / graphql # 5-using-the-graphql-api`,
),
)
module.exports = {Habit}
Nous utilisons la méthode makeSchema
du paquet nexus
pour combiner notre modèle Habit
et nous ajoutons la requête
et Mutation
aux types
. Nous ajoutons également nexusPrismaPlugin
à notre tableau de plugins
. Enfin, nous démarrons notre serveur à localhost: 4000 . Le port 4000 est le port par défaut pour graphql-yoga . Vous pouvez changer le port comme suggéré ici .
Commençons maintenant le serveur. Mais d’abord, nous devons nous assurer que nos dernières modifications de schéma sont écrites dans le répertoire node_modules / @ généré / photon
. Cela se produit lorsque vous exécutez prisma2 générer
.
Si vous n'avez pas installé prisma2
globalement, vous devrez remplacer prisma2 générer
par . ./node_modules/.bin/prisma2 génère
. Nous devons ensuite migrer notre base de données pour créer des tables.
Migrer votre base de données avec Lift
La migration de votre base de données avec Lift s'effectue en deux étapes:
- Enregistrez une nouvelle migration (les migrations sont représentées sous forme de répertoires dans le fichier). system)
- Exécutez la migration (pour migrer le schéma de la base de données sous-jacente)
Dans les commandes CLI, ces étapes peuvent être effectuées de la manière suivante (les étapes de l'interface de ligne de commande sont en cours de mise à jour):
$ prisma2 lift save --name 'init'
$ prisma2 lift up
Encore une fois, vous devez remplacer prisma2
par ./ node_modules / .bin / prisma2
si vous ne l'avez pas installé globalement.
Le processus de migration est à présent terminé. terminé. Nous avons créé la table avec succès. Nous pouvons maintenant ensemencer notre base de données avec les valeurs initiales.
Continuez et exécutez la commande suivante dans le terminal:
$ yarn seed
Cela ensemencera notre base de données avec huit habitudes, comme indiqué dans notre fichier seed.js
.
Vous pouvez maintenant exécuter le serveur en tapant:
$ yarn dev
Votre serveur sera exécuté à l'emplacement localhost: 4000 que vous pourrez ouvrir et interroger toutes les API que vous avez créées.
Répertoriez toutes les habitudes
.
des habitudes {
identifiant
prénom
traînée
}
}
Trouvez une habitude par son nom
requête findHabitByName {
habitude (où: {name: "Workout"}) {
identifiant
prénom
traînée
}
}
Créez une habitude
mutation createHabit {
createHabit (données: {nom: "Natation", séquence: 10}) {
identifiant
prénom
traînée
}
}
Supprimer l'habitude
mutation deleteHabit {
deleteHabit (où: {id: "ck2kinq2j0001xqv5ski2byvs"}) {
identifiant
prénom
traînée
}
}
Incrément de séquence
mutation incrementStreak {
incrementStreak (name: "Workout") {
traînée
}
}
C'est tout ce dont nous avons besoin pour la partie arrière. Commençons dès maintenant.
Front End (côté client)
Démarrez un nouveau projet React
Démarrez un nouveau projet React en utilisant create-react-app . Utilisez npx pour amorcer un nouveau projet sans avoir à installer le create-react-app
globalement en procédant comme suit:
$ npx create-react-app client
Vous pouvez également installer create-react-app
globalement et amorcer un nouveau projet React, puis procéder comme suit:
$ yarn global add créer-react-app // ou npm install - application globale de création-réaction
$ client create-react-app
Ceci démarre un nouveau projet React utilisant créez-vous-appliquez-le
.
Maintenant, allez dans le répertoire client /
exécutez le projet et tapez ceci:
$ cd client
$ début de fil
Le côté client sera exécuté sur localhost: 3000 .
Il devrait maintenant ressembler à ceci:
Entrez maintenant le répertoire src /
et supprimez les fichiers inutiles tels que App.css
App.test.js
index.css
et logo.svg
:
$ cd src
$ rm App.css App.test.js index.css logo.svg
Supprimer les références aux fichiers supprimés des index.js
et App.js
.
index.js
devrait maintenant ressembler à ceci: [19659058] import Réagit de "réagit";
importer ReactDOM de "react-dom";
importer l'application depuis "./App";
importer * en tant que serviceWorker à partir de "./serviceWorker";
ReactDOM.render (document.getElementById ("racine"));
// Si vous souhaitez que votre application fonctionne hors connexion et se charge plus rapidement, vous pouvez modifier
// unregister () pour vous inscrire () ci-dessous. Notez que cela vient avec quelques pièges.
// En savoir plus sur les travailleurs du service: https://bit.ly/CRA-PWA
serviceWorker.unregister ();
Et assurez-vous que votre App.js
ressemble à ceci:
import Réagissez à partir de 'réagir'
fonction App () {
retour Application Stries
}
exportation par défaut
urql: Langage universel pour les requêtes de réaction
Allez-y et installez-le d'abord urql qui est une alternative à Apollo Client . Nous devons également installer graphql
car il s’agit d’une dépendance entre pairs de urql
. Vous pouvez le faire en tapant la commande suivante dans le terminal:
$ cd .. // sort du répertoire "src /" et dans le répertoire "client /"
$ fil ajouter urql graphql
À présent, connectez urql
au serveur Prisma GraphQL en modifiant App.js
comme suit:
import Réagissez à partir de 'react'
importer {createClient, Provider} de 'urql'
const client = createClient ({
url: 'http: // localhost: 4000 /'
})
const App = () => (
Streaks App
)
exportation par défaut
Nous utilisons ici la fonction createClient
de urql
en passant à notre url
puis en lui passant une valeur
. ] support du composant Provider
. Cela nous permet d'interroger, de muter ou de souscrire à n'importe quel composant qui est l'enfant du composant Provider
.
Il devrait maintenant ressembler à ceci:
Interface utilisateur Chakra
Dans ce didacticiel, nous utiliserons Interface utilisateur Chakra comme bibliothèque de composants pour réaliser rapidement de belles applications. Il s'agit d'un type de bibliothèque de composants différent conçu pour l'accessibilité et la rapidité. C'est complètement thématique et composable. Pour l'installer, tapez ce qui suit dans le terminal:
$ yarn add @ chakra-ui / core @ emotion / core @ emotion / styled emotion-theming
Chakra utilise Emotion sous le capot, nous devons donc l'installer et ses dépendances homologues.
Dans ce tutoriel, nous avons également besoin de graphql-tag
pour analyser notre GraphQL. requêtes, réagissent-icônes
pour montrer de belles icônes, @ seznam / compose-react-refs
pour composer plusieurs références et réagissent-crochet-forme pour créer des formulaires.
Assurez-vous également de les installer en tapant ce qui suit dans le terminal:
$ yarn add graphql-tag react-icons @ seznam / compose-react-refs react-hook-form
Maintenant, allez-y et changez App.js
comme suit:
import {Text, ThemeProvider} de '@ chakra-ui / core'
importer Réagir de 'réagir'
importer {createClient, Provider} de 'urql'
const client = createClient ({
url: 'http: // localhost: 4000 /'
})
const App = () => (
<>
>
)
exportation par défaut
Nous avons importé Texte et ThemeProvider
de @ chakra-ui / core
.
Le composant
est utilisé pour rendre le texte et des paragraphes dans une interface. Il rend par défaut une balise
.
Nous fabriquons nos composants Text
fontSize
sous la forme 5xl
et nous l'alignons au centre.
Nous enveloppons également le tout dans ThemeProvider
. ThemeProvider
nous permet d'ajouter un thème à notre application en passant à l'objet theme
comme accessoire. Chakra UI est livré avec un thème par défaut que nous verrons si nous plaçons ThemeProvider
au-dessus de nos composants. La disposition ressemble maintenant à ceci:
Essayez de supprimer ThemeProvider
pour voir comment il affecte la présentation. Il ressemble à ceci:
Remettez-le en place. Codons maintenant notre application.
À présent, créez un composant .
et un dossier graphql
:
$ mkdir components graphql
Rendez-vous dans le dossier graphql
et créez des fichiers nommés createHabit.js
deleteHabit.js
incrementStreak.js
] listAllHabits.js
et index.js
.
$ cd graphql
$ touch createHabit.js deleteHabit.js incrementStreak.js listAllHabits.js index.js
Répertoriez toutes les habitudes
Ouvrez listAllHabits.js
et collez le texte suivant:
import gql depuis 'graphql-tag'
export const LIST_ALL_HABITS_QUERY = gql`
liste de requêtesAllHabits {
des habitudes {
identifiant
prénom
traînée
}
}
`
Notez que la requête ci-dessus
est similaire à celle que nous avons saisie dans l'éditeur GraphiQL. C'est comment GraphQL est utilisé. Tout d'abord, nous saisissons la mutation de la requête
ou
dans l'éditeur GraphiQL pour voir si elle donne les données dont nous avons besoin, puis nous les copions-collons dans l'application.
Créer habitude mutation
Inside createHabit.js
collez ce qui suit:
import gql depuis 'graphql-tag'
exportation CREATE_HABIT_MUTATION = gql`
mutation createHabit ($ name: String !, $ streak: Int!) {
createHabit (data: {name: $ name, streak: $ streak}) {
identifiant
prénom
traînée
}
}
`
Encore une fois, nous avons copié la mutation
de notre éditeur GraphiQL ci-dessus. La principale différence est que nous avons remplacé la valeur codée en dur par une variable notée $
afin que nous puissions saisir ce que l'utilisateur a spécifié. La mutation ci-dessus sera utilisée pour créer une habitude.
Supprimer la mutation d'habitude
Collez les éléments suivants dans deleteHabit.js
:
import gql de 'graphql-tag'
export const DELETE_HABIT_MUTATION = gql`
mutation deleteHabit ($ id: ID!) {
deleteHabit (où: {id: $ id}) {
identifiant
prénom
traînée
}
}
`
La mutation ci-dessus sera utilisée pour supprimer une habitude.
Mutation incrémentielle
Collez ce qui suit dans incrementStreak.js
:
import gql depuis 'graphql-tag'
export const INCREMENT_STREAK_MUTATION = gql`
mutation incrementStreak ($ name: String) {
incrementStreak (name: $ name) {
traînée
}
}
`
La mutation ci-dessus sera utilisée pour incrémenter la traînée d'une habitude donnée.
Enfin, pour faciliter l'importation
de tous les éléments d'un fichier, collez ce qui suit dans index.js
:
exportation * de './createHabit'
export * de './deleteHabit'
export * depuis './incrementStreak'
export * de './listAllHabits'
Cela nous permet d'importer
des éléments d'un fichier unique au lieu de quatre fichiers différents. Ceci est bénéfique lorsque nous avons 10s de requêtes
et mutations
.
Maintenant, allez dans le répertoire components /
et créez des fichiers nommés CreateHabit.js
DeleteHabit.js
Habit.js
ListAllHabits.js
et index.js
.
. $ 1965 cd. ./Composants/
$ touch CreateHabit.js DeleteHabit.js Habit.js ListAllHabits.js index.js
Nous allons toucher le reste des fichiers plus loin dans ce didacticiel, mais pour l'instant ouvrez index.js
et collez ce qui suit:
export * de './Common/Error'
export * de './Common/Loading'
export * depuis './CreateHabit'
export * de './DeleteHabit'
exportation * de './Habit'
export * depuis './ListAllHabits'
Créez maintenant un dossier Common /
et à l'intérieur de celui-ci Loading.js
et Error.js
:
$ mkdir Common && cd $ _
$ touch Loading.js Error.js
cd $ _
nous permet d’entrer dans le répertoire Common
immédiatement après sa création. Ensuite, nous créons Loading.js
et Error.js
à l'intérieur.
Créez maintenant un dossier utils /
à l'intérieur du src /
. répertoire contenant deux fichiers – getIcon.js
et index.js
:
$ cd ../../
$ mkdir utils / && cd $ _
$ touch getIcon.js index.js
Créez des icônes pour les habitudes
Ouvrez maintenant getIcon.js
et collez le texte suivant:
import {AiOutlineQuestion} depuis 'react-icons / ai'
importer {FaCode, FaRunning, FaSwimmer} à partir de 'react-icons / fa'
importer {FiPhoneCall} de 'react-icons / fi'
importer {
GiCycling,
GiMeditation,
GiMuscleUp,
GiTennisRacket,
} de 'react-icons / gi'
importer {MdSmokeFree} à partir de 'react-icons / md'
icônes const = [
{
keywords: ['call', 'phone'],
photo: FiPhoneCall,
},
{
mots-clés: ['workout', 'muscle', 'body-building', 'body building'],
photo: GiMuscleUp,
},
{
mots-clés: ['cycling', 'cycle'],
photo: GiCycling,
},
{
mots-clés: ['running', 'run'],
photo: FaRunning,
},
{
mots-clés: ['swimming', 'swim'],
photo: FaSwimmer,
},
{
mots-clés: ['racket', 'tennis', 'badminton'],
image: GiTennisRacket,
},
{
mots-clés: [
'smoke',
'smoking',
'no smoking',
'no-smoking',
'smoke free',
'no smoke',
],
pic: MdSmokeFree,
},
{
mots-clés: ['code', 'code everyday', 'program', 'programming'],
image: FaCode,
},
{
mots-clés: ['meditate', 'meditation'],
photo: GiMeditation,
},
]
export const getIcon = nom => {
let icon = AiOutlineQuestion
pour (soit i = 0; i
lowerCaseName.includes (mot-clé),
)
if (doesKeywordExistInName) {
icône = pic
Pause
}
}
icône de retour
}
Il s'agit d'un fichier d'assistance contenant une fonction unique appelée getIcon
. Il prend un nom d'habitude et retourne une icône appropriée. Pour ajouter plus d'icônes, vous devez ajouter un objet au tableau icons
avec les mots-clés appropriés
et pic
qui peuvent être importés à partir de react- icons .
Importons cette fonction de index.js
pour pouvoir l’importer facilement sans avoir à mémoriser le nom du fichier. Ceci n’est pas nécessaire ici, mais il est utile lorsque l’application devient volumineuse.
Ouvrez index.js
et collez le une ligne suivant:
export * from './getIcon'.
Allez-y et ouvrez Loading.js
et collez ce qui suit:
import {Flex, Spinner} depuis '@ chakra-ui / core'
importer Réagir de 'réagir'
export const Chargement = () => (
)
Nous montrons un beau Spinner
que nous avons importé de la bibliothèque Chakra UI. Nous l'enveloppons dans un composant Flex
qui facilite l'application de Flexbox sans avoir à écrire de code CSS. À mon avis, Chakra permet de créer facilement de belles applications plus rapidement sans avoir à écrire de code CSS personnalisé.
Ouvrez maintenant Error.js
et collez le texte suivant:
import {
Alerte,
AlertDescription,
AlertIcon,
AlertTitle,
Fléchir,
} de '@ chakra-ui / core'
importer Réagir de 'réagir'
export const Erreur = () => (
Oups,
il y a eu une erreur. Veuillez réessayer plus tard!
)
Nous montrons ici une boîte d'erreur. Vous pouvez facilement trouver le code ci-dessus dans la documentation de Chakra UI. Aucune science de fusée ici. Tout simplement un ancien copier-coller.
Afficher une habitude
Ouvrez Habit.js
et collez le texte suivant:
import {Badge, Boîte, Flex, Texte} de '@chakra -ui / core '
importer Réagir de 'réagir'
importer {useMutation} depuis 'urql'
importer {INCREMENT_STREAK_MUTATION} de '../graphql/index'
importer {getIcon} de '../utils/index'
couleurs const = [
'tomato',
'green.400',
'yellow.300',
'cornflowerblue',
'antiquewhite',
'aquamarine',
'lightpink',
'navajowhite',
'red.500',
'lightcoral'
]
export const Habit = ({index, habit}) => {
const {id, name, streak} = habitude
const bgColor = colors [index % colors.length]
const [res, executeMutation] = useMutation (INCREMENT_STREAK_MUTATION) // ligne eslint-disable-line no-inutilisée-vars
revenir (
)
}
Le composant Habit
affiche une seule habitude
avec un badge [Strande]
. Il prend en index
et l'habitude
. Nous utilisons index
pour faire pivoter les couleurs de fond d'un habitude
du tableau de couleurs
.
Dans le composant Flex
nous affichons une icône
en appelant la boîte
. composant avec un comme
prop. Le as
est utilisé pour remplacer le composant Box
Box par défaut
div
par tout autre élément spécifié dans le par
prop. Donc, dans ce cas, nous allons le remplacer par la valeur de retour de getIcon
qui est une icône
de de réag-icons
.
nous affichons le nom
à l'intérieur du composant Text
et enveloppons la séquence
avec le composant Badge
. La série
lorsque vous cliquez dessus, appelle la commande INCREMENT_STREAK_MUTATION
que nous avons définie ci-dessus avec la fonction urql
. We pass the appropriate habit name
to the function so that we can increment that specific habit.
Display a list of habits
Open ListAllHabits.js
and paste the following:
import { Flex, Text } from '@chakra-ui/core'
import React from 'react'
import { useQuery } from 'urql'
import { LIST_ALL_HABITS_QUERY } from '../graphql/index'
import { Error, Habit, Loading } from './index'
export const ListAllHabits = () => {
const [{ fetching, error, data }] = useQuery({ query: LIST_ALL_HABITS_QUERY })
if (fetching) return
if (error) return
const noHabits = !data.habits.length
return (
{noHabits && (
)}
{data.habits.map((habit, i) => (
))}
)
}
Here, we fetch all habits by calling in urql
‘s useQuery
function by passing in LIST_ALL_HABITS_QUERY
. It gives back fetching
error
and data
.
When fetching
is true
we display the Loading
component, which shows Spinner
.
When error
is true
we display the Error
component, which displays an Alert
.
Later, we check if there exist any habits
and if there aren’t any habits
then we display You currently track 0 habits. Add one.
If we have any habits
we display them so it looks like this:
Try clicking on the streak
badge to see it increase.
Delete a habit
Now, go ahead and open up DeleteHabit.js
and paste the following:
import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
Button,
IconButton,
} from '@chakra-ui/core'
import React from 'react'
import { useMutation } from 'urql'
import { DELETE_HABIT_MUTATION } from '../graphql/index'
export const DeleteHabit = ({ id, name }) => {
const [isOpen, setIsOpen] = React.useState()
const onClose = () => setIsOpen(false)
const cancelRef = React.useRef()
const [res, executeMutation] = useMutation(DELETE_HABIT_MUTATION) // eslint-disable-line no-unused-vars
const deleteHabit = () => {
executeMutation({ id })
onClose()
}
return (
<>
setIsOpen(true)}
/>
Delete “{name}” Habit
Are you sure? You can't undo this action afterwards.
>
)
}
Most of this code is grabbed from Chakra UI’s AlertDialog. The main objective of this component is to show a trash
icon when clicked alerts a modal with two buttons Cancel
and Delete
. On clicking Cancel
it calls the onClose
function, which makes the modal disappear, and on clicking Delete
it calls the deleteHabit
function.
The deleteHabit
function calls the DELETE_HABIT_MUTATION
while passing it the id
it gets from the parent component and closes the modal by calling onClose
.
Now again open up Habit.js
and add the following import to the top:
import { DeleteHabit } from './index'
And now just below closing Badge
component, add the following code:
The whole Habit.js
file should now look like this:
import { Badge, Box, Flex, Text } from '@chakra-ui/core'
import React from 'react'
import { useMutation } from 'urql'
import { INCREMENT_STREAK_MUTATION } from '../graphql/index'
import { getIcon } from '../utils/index'
import { DeleteHabit } from './index'
const colors = [
'tomato',
'green.400',
'yellow.300',
'cornflowerblue',
'antiquewhite',
'aquamarine',
'lightpink',
'navajowhite',
'red.500',
'lightcoral'
]
export const Habit = ({ index, habit }) => {
const { id, name, streak } = habit
const bgColor = colors[index % colors.length]
const [res, executeMutation] = useMutation(INCREMENT_STREAK_MUTATION) // eslint-disable-line no-unused-vars
return (
)
}
It should now look like this:
Now try clicking the trash
icon on any of the habits. It should open up a modal as follows:
If you click Cancelit will just close the modal. If you click Deletethe habit will be removed from the UI and the Prisma Database itself as follows:
Create a habit
Now let’s open up CreateHabit.js
and paste the following:
import {
Button,
Flex,
FormControl,
FormLabel,
Icon,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
useDisclosure,
} from '@chakra-ui/core'
import composeRefs from '@seznam/compose-react-refs'
import React, { useRef } from 'react'
import useForm from 'react-hook-form'
import { useMutation } from 'urql'
import { CREATE_HABIT_MUTATION } from '../graphql/index'
export const CreateHabit = () => {
const { handleSubmit, register } = useForm()
const { isOpen, onOpen, onClose } = useDisclosure()
const [res, executeMutation] = useMutation(CREATE_HABIT_MUTATION) // eslint-disable-line no-unused-vars
const initialRef = useRef()
const finalRef = useRef()
const onSubmit = (values, e) => {
const { name, streak } = values
executeMutation({
name,
streak: +streak,
})
e.target.reset()
onClose()
}
return (
Create Habit
)
}
Again, most of this content is copied from Chakra UI’s FormControl. Here, we show a +
icon to the user, which we bring in from Chakra’s own Icon component.
When the +
icon is clicked, we open up a modal that uses react-hook-form.
React Hook Form is the easiest way to build forms with Hooks. We just need to pass in register
to the ref
s of the input
s we want to track. We get the register
when we call the hook useForm
from react-hook-form
. We also get handleSubmit
which we need to pass to the form
component. We need to pass handleSubmit
a function. In our case, we pass onSubmit
and the first parameter values
of this function are the values we get, which are entered by the user.
One important thing to note here is that we use composeRefs
from @seznam/compose-react-refs
to compose multiple refs. This is needed because we need to provide the register
ref to register our React Hook Form and to keep track of the value. And the second ref initialRef
is needed because we need it to focus on the first input as soon as the popup appears. This is necessary for accessibility as well for those who are using screen readers.
Finally, when we call onSubmit
we check if it’s not empty and then we call the mutation with two parameters name
and streak
. +streak
means the String
is coerced into a Number
. Basically, all values returned from React Hook Form are strings
but in our back end, we’re expecting a number
.
Lastly, we reset
the form to clear all the values and input states. And then we close the modal.
Now go ahead and import CreateHabit
into ListAllHabits.js
at the top:
import { CreateHabit, Error, Habit, Loading } from './index'
Also, make sure to include it just above where you list all habits using Array.map()
as follows:
The ListAllHabits.js
file must now look like this:
import { Flex, Text } from '@chakra-ui/core'
import React from 'react'
import { useQuery } from 'urql'
import { LIST_ALL_HABITS_QUERY } from '../graphql/index'
import { CreateHabit, Error, Habit, Loading } from './index'
export const ListAllHabits = () => {
const [{ fetching, error, data }] = useQuery({ query: LIST_ALL_HABITS_QUERY })
if (fetching) return
if (error) return
const noHabits = !data.habits.length
return (
{noHabits && (
)}
{data.habits.map((habit, i) => (
))}
)
}
It should now show the +
sign as follows:
Now click the +
sign and add our Workout
habit with 50
streaks that we deleted.
Once you click Save
notice it immediately gets added.
You can add a bunch of other habits that you want to track. After adding a bunch of habits, it now looks like:
Conclusion
In this tutorial, we built a complete habit tracker app “Streaks” from scratch. We used Chakra UI as our React component library to make a beautiful, accessible application with speed. Chakra UI helped us create alerts, modals, and spinners by just adding the built-in building blocks so we could focus on writing the logic rather than writing CSS.
We used React Hooks Form to create simple and easy forms by using React Hooks. It allowed us to keep our forms DRY without writing a lot of code.
In our back end, we used The Prisma Framework. We used Prisma’s own Photon to create data-models declaratively and Lift to perform database migrations. Prisma makes it simple to query the database by using static typing, which allows us to code with confidence. The built-in autocompletion allows us to write applications at a lightning speed.
While The Prisma Framework is in betayou can have fun with it in your side projects. It will soon be out, so stay tuned.
Now go on and create your own full-stack applications with confidence.
Source link