Fermer

décembre 5, 2019

Construire un outil de suivi des habitudes avec Prisma 2, l'interface utilisateur Chakra et React –


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:

 Prisma 1 architecture

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:

  1. Photon : un type de base de données non sécurisée et générée automatiquement («remplacement ORM»)
  2. Lift : un système de migration déclaratif avec des flux de travail personnalisés
  3. 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 .

 Architecture Prisma 2

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:

  1. Sélectionnez Kit de démarrage
  2. Sélectionnez JavaScript
  3. Sélectionnez API GraphQL
  4. 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ù. 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:

  1. Enregistrez une nouvelle migration (les migrations sont représentées sous forme de répertoires dans le fichier). system)
  2. 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
  }
}

 Application Streaks - Liste des habitudes

Trouvez une habitude par son nom

 requête findHabitByName {
  habitude (où: {name: "Workout"}) {
    identifiant
    prénom
    traînée
  }
}

 Application Stries - Trouvez une habitude par nom

Créez une habitude

 mutation createHabit {
  createHabit (données: {nom: "Natation", séquence: 10}) {
    identifiant
    prénom
    traînée
  }
}

 Application Streaks - Créer une habitude

Supprimer l'habitude

 mutation deleteHabit {
  deleteHabit (où: {id: "ck2kinq2j0001xqv5ski2byvs"}) {
    identifiant
    prénom
    traînée
  }
}

 Application Stries - Supprimer l'habitude

Incrément de séquence

 mutation incrementStreak {
  incrementStreak (name: "Workout") {
    traînée
  }
}

 Application Streaks - Incrément Streak

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:

 Créer une application React - Init

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:

 Application Streaks - Init

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 = () => (
  
    
       <>
        
          Streaks 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:

 Application Streaks - Chakra UI Init

Essayez de supprimer ThemeProvider pour voir comment il affecte la présentation. Il ressemble à ceci:

 Streaks App - Initiation de l'interface utilisateur de Chakra Remove ThemeProvider

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 < icons.length; i++) {
    const { keywords, pic } = icons[i]
    const lowerCaseName = name.toLowerCase()
    const doesKeywordExistInName = keywords.some(keyword =>
      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 (
    
      
      
         {name}
         executeMutation ({name})}
        >
          {traînée}
        
      
    
  )
}

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 && (
        
          You currently track 0 habits. Add one.
        
      )}
      {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 fetchingerror and data.

When fetching is truewe display the Loading component, which shows Spinner.

When error is truewe display the Error component, which displays an Alert.

Later, we check if there exist any habitsand if there aren’t any habits then we display You currently track 0 habits. Add one.

Streaks App - No Habits

If we have any habitswe display them so it looks like this:

Streaks App - List Habits

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 Cancelit 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 (
    
      
      
        {name}
         executeMutation({ name })}
        >
          {streak}
        
        
      
    
  )
}

It should now look like this:

Streaks App - Delete Habit

Now try clicking the trash icon on any of the habits. It should open up a modal as follows:

Streaks App - Delete Habit Show Modal

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:

Streaks App - Delete Habit Workout

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
          
          
Habit name Streak
) }

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 refs of the inputs we want to track. We get the register when we call the hook useForm from react-hook-form. We also get handleSubmitwhich 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 stringsbut 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 && (
        
          You currently track 0 habits. Add one.
        
      )}
      
      {data.habits.map((habit, i) => (
        
      ))}
    
  )
}

It should now show the + sign as follows:

Streaks App - Plus Sign

Now click the + sign and add our Workout habit with 50 streaks that we deleted.

Streaks App - Add Workout Habit

Once you click Savenotice it immediately gets added.

Streaks App - Workout Habit 50 Streak

You can add a bunch of other habits that you want to track. After adding a bunch of habits, it now looks like:

treaks App - Complete

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