Dans cet article, nous allons vous montrer comment créer simplement un Blog avec React JS et Strapi.

Strapi est un système de gestion de contenu open source et facile à utiliser, de plus, il fonctionne à merveille avec React.

Tout d'abord préparez votre espace de travail et créez un dossier avec dans lequel vous placerez votre projet. Appelez-le Strapi-Blog et accédez-y. Personnellement, je travaille plus avec Yarn que NPM mais les deux peuvent être utilisés.  Donc, sur votre console, écrivez...

yarn create strapi-app backend --quickstart --no-run

Cette ligne de commande unique créera tout ce dont vous avez besoin pour votre back-end. Assurez-vous d'ajouter l'indicateur --no-run , cela empêchera votre application de démarrer automatiquement le serveur car nous aurons besoin d'ajouter plus de plugins à Strapi plus tard.

Maintenant que vous savez que vous devez installer des plugins pour améliorer votre application, installez l'un des plus populaires: le plugin graphql.

Une fois l'installation terminée, vous pouvez enfin démarrer votre serveur Strapi et vous y inscrire.

Strapi

Strapi fonctionne sur: http://localhost:1337 .

Il est maintenant temps de démarrer la partie front-end avec React.

  • Créez un serveur front-end React en exécutant la commande suivante:

yarn create react-app frontend

Une fois l'installation terminée, vous pouvez démarrer votre application front-end pour vous assurer que tout s'est bien passé.

cd frontend
yarn dev

Vous devez encore y ajouter certaines choses.

Commencez par ajouter react-router-dom en tapant la commande suivante: yarn add react-router-dom

Maintenant, supprimez tout ce qui se trouve dans votre dossier src, vous n'en avez plus besoin.

Créez un fichier index.js dans le src contenant le code suivant:

import React from "react";
import ReactDOM from "react-dom";
import App from "./containers/App";
import { BrowserRouter as Router } from "react-router-dom";

ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById("root")
);

Si vous vous interrogez sur le fichier App, il sera placé dans un dossier containers.

  • Créez un dossier containers/App et un fichier index.js à l'intérieur contenant le code suivant:
import React from "react";

function App() {
  return <div className="App" />;
}

export default App;

Pour rendre votre blog esthétique, utilisez un framework CSS populaire pour le rendre plus stylé: UiKit et Apollo pour la requête Strapi avec GraphQL.

Ajoutez la ligne suivante dans votre public/index.html afin d'utiliser Uikit depuis leur CDN.

...
<title>React App</title>
<link
      rel="stylesheet"
      href="https://fonts.googleapis.com/css?family=Staatliches"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/css/uikit.min.css"
    />

    <script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/js/uikit-icons.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.js"></script>
...
  • Créez un fichier ./src/index.css contenant le style suivant:
a {
  text-decoration: none;
}

h1 {
  font-family: Staatliches;
  font-size: 120px;
}

#category {
  font-family: Staatliches;
  font-weight: 500;
}

#title {
  letter-spacing: 0.4px;
  font-size: 22px;
  font-size: 1.375rem;
  line-height: 1.13636;
}

#banner {
  margin: 20px;
  height: 800px;
}

#editor {
  font-size: 16px;
  font-size: 1rem;
  line-height: 1.75;
}

.uk-navbar-container {
  background: #fff !important;
  font-family: Staatliches;
}

img:hover {
  opacity: 1;
  transition: opacity 0.25s cubic-bezier(0.39, 0.575, 0.565, 1);
}


Vous devez maintenant ajouter la dépendance apollo à votre projet afin de communiquer avec votre back-office.

Exécutez la commande suivante:

yarn add apollo-boost @apollo/react-hooks graphql react-apollo

Et vous aurez besoin de créer un dossier qui prendra en charge cette communication.

  • Créez un fichier ./src/utils/apolloClient.js contenant le code suivant:
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";

const cache = new InMemoryCache();
const link = new HttpLink({
  uri: `${process.env.REACT_APP_BACKEND_URL}/graphql`
});
const client = new ApolloClient({
  cache,
  link
});

export default client;

Ensuite, créez un fichier .env dans le "root" de votre application contenant la variable d'environnement REACT_APP_BACKEND_URL comme suit: REACT_APP_BACKEND_URL="http://localhost:1337"

  • Vous devrez ensuite mettre votre App/index.js à l'intérieur de ApolloProvider et importer votre fichier index.css:
import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider } from "react-apollo";
import App from "./containers/App";
import client from "./utils/apolloClient";
import { BrowserRouter as Router } from "react-router-dom";
import "./index.css";

ReactDOM.render(
  <Router>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </Router>,
  document.getElementById("root")
);

Génial, tout s'est bien passé, vous devriez avoir une page vierge, alors faisons quelques articles à afficher.

Plongez dans votre panneau d'administration Strapi et cliquez sur le lien Content Type Builder dans la barre latérale.

Cliquez sur Create new content-type et appelez-le article.

Vous serez maintenant invité à créer tous les champs pour votre type de contenu:

  • Créez les champs suivants:
  • title avec le modèle Text (obligatoire)
  • content avec le modèle Rich Text (obligatoire)
  • image avec le modèle Media (Single image) (obligatoire)
  • published_at avec le modèle date (obligatoire)

Appuyez sur Enregistrer! Voilà, votre premier type de contenu a été créé. Vous pouvez maintenant créer votre premier article, mais vous avez une chose à faire avant cela: Donner l'accès de l'article aux lecteurs.

  • Cliquez sur l'icône Roles & Permission et cliquez sur le mode public.
  • Consultez l'article grâce aux itinéraires find et findone et enregistrez.

Maintenant, écrivez votre premier article.

Si vous allez sur http://localhost:1337/articles, vous le trouverez!

Créez des rubriques

Vous pouvez attribuer une rubrique à votre article (actualités, tendances, blog). Vous allez le faire en créant un autre type de contenu dans Strapi.

  • Créez un type de contenu category avec le champ suivant
  • name avec un type "Text"

Cliquez sur "enregistrer"!

  • Créez un nouveau champ au sein du type de contenu Article qui aura pour "Relation" Category has many Articles
  • Cliquez sur l'icône Roles & Permission et cliquez sur le mode public puis vérifiez grâce aux itinéraires find et findone et enregistrez.

Vous pourrez maintenant sélectionner une catégorie pour votre article dans la zone latérale droite.

Maintenant que tout est ok avec Strapi, travaillez sur la partie front-end!

Créez le composant Query

Vous utiliserez Apollo pour récupérer vos données à partir des différentes pages. Nous ne voulons pas que vous réécriviez le même code à chaque fois dans vos pages. C'est pourquoi vous allez écrire un composant Query qui sera réutilisable!

  • Créez ./src/components/Query/index.js contenant le code suivant:
import React from "react";
import { useQuery } from "@apollo/react-hooks";

const Query = ({ children, query, id }) => {
  const { data, loading, error } = useQuery(query, {
    variables: { id: id }
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {JSON.stringify(error)}</p>;
  return children({ data });
};

export default Query;

Vous utiliserez un hook useQuery pour appeler votre serveur Strapi à cette adresse http://localhost:1337/graphql. Un id vous sera envoyé s'il existe (il sera nécessaire lorsque vous voudrez chercher un seul article).

Essayez de créez votre barre de navigation qui récupérera toutes vos catégories, mais créez d'abord la requête GraphQL.

  • Créez un fichier ./src/queries/category/categories.js contenant le code suivant:
import gql from "graphql-tag";

const CATEGORIES_QUERY = gql`
  query Categories {
    categories {
      id
      name
    }
  }
`;

export default CATEGORIES_QUERY;

Utilisez cette requête pour afficher vos catégories dans votre barre de navigation.

  • Créez un fichier ./src/components/Nav/index.js contenant le code suivant:
import React from "react";
import Query from "../Query";
import { Link } from "react-router-dom";

import CATEGORIES_QUERY from "../../queries/category/categories";

const Nav = () => {
  return (
    <div>
      <Query query={CATEGORIES_QUERY} id={null}>
        {({ data: { categories } }) => {
          return (
            <div>
              <nav className="uk-navbar-container" data-uk-navbar>
                <div className="uk-navbar-left">
                  <ul className="uk-navbar-nav">
                    <li>
                      <Link to="/">Strapi Blog</Link>
                    </li>
                  </ul>
                </div>

                <div className="uk-navbar-right">
                  <ul className="uk-navbar-nav">
                    {categories.map((category, i) => {
                      return (
                        <li key={category.id}>
                          <Link
                            to={`/category/${category.id}`}
                            className="uk-link-reset"
                          >
                            {category.name}
                          </Link>
                        </li>
                      );
                    })}
                  </ul>
                </div>
              </nav>
            </div>
          );
        }}
      </Query>
    </div>
  );
};

export default Nav;

Puisque vous voulez que votre barre de navigation soit dans toutes les pages de votre application, vous allez l'utiliser dans votre App Container:

  • Importez et déclarez votre composant de navigation dans containers/App/index.js
import React from "react";
import Nav from "../../components/Nav";

function App() {
  return (
    <div className="App">
      <Nav />
    </div>
  );
}

export default App;

Vous devriez maintenant pouvoir voir votre toute nouvelle barre de navigation contenant vos catégories. Mais les liens ne fonctionnent pas pour le moment. Nous y reviendrons plus tard, ne vous inquiétez pas.

Créer les conteneurs "Articles"

Ce conteneur englobera un composant qui affichera tous vos articles.

  • Créez un fichier containers/Articles/index.js contenant le code suivant:
import React from "react";
import Articles from "../../components/Articles";
import Query from "../../components/Query";
import ARTICLES_QUERY from "../../queries/article/articles";

const Home = () => {
  return (
    <div>
      <div className="uk-section">
        <div className="uk-container uk-container-large">
          <h1>Strapi blog</h1>
          <Query query={ARTICLES_QUERY}>
            {({ data: { articles } }) => {
              return <Articles articles={articles} />;
            }}
          </Query>
        </div>
      </div>
    </div>
  );
};

export default Home;

Écrivez la requête qui récupère tous vos articles:

  • Créez un fichier ./src/queries/articles/articles.js contenant le code suivant:
import gql from "graphql-tag";

const ARTICLES_QUERY = gql`
  query Articles {
    articles {
      id
      title
      category {
        id
        name
      }
      image {
        url
      }
    }
  }
`;

export default ARTICLES_QUERY;

Vous devez maintenant créer un composant Articles qui affichera tous vos articles et un composant "Card" qui affichera chacun de vos articles:

  • Créez un fichier components/Articles/index.js contenant les éléments suivants:
import React from "react";
import Card from "../Card";

const Articles = ({ articles }) => {
  const leftArticlesCount = Math.ceil(articles.length / 5);
  const leftArticles = articles.slice(0, leftArticlesCount);
  const rightArticles = articles.slice(leftArticlesCount, articles.length);

  return (
    <div>
      <div className="uk-child-width-1-2" data-uk-grid>
        <div>
          {leftArticles.map((article, i) => {
            return <Card article={article} key={`article__${article.id}`} />;
          })}
        </div>
        <div>
          <div className="uk-child-width-1-2@m uk-grid-match" data-uk-grid>
            {rightArticles.map((article, i) => {
              return <Card article={article} key={`article__${article.id}`} />;
            })}
          </div>
        </div>
      </div>
    </div>
  );
};

export default Articles;
  • Créez un fichier components/Card/index.js contenant les éléments suivants:
import React from "react";
import { Link } from "react-router-dom";

const Card = ({ article }) => {
  const imageUrl =
    process.env.NODE_ENV !== "development"
      ? article.image.url
      : process.env.REACT_APP_BACKEND_URL + article.image.url;
  return (
    <Link to={`/article/${article.id}`} className="uk-link-reset">
      <div className="uk-card uk-card-muted">
        <div className="uk-card-media-top">
          <img
            src={imageUrl}
            alt={article.image.url}
            height="100"
          />
        </div>
        <div className="uk-card-body">
          <p id="category" className="uk-text-uppercase">
            {article.category.name}
          </p>
          <p id="title" className="uk-text-large">
            {article.title}
          </p>
        </div>
      </div>
    </Link>
  );
};

export default Card;

Tout est prêt, il suffit d'importer le conteneur "Articles" dans le App container.

  • Importez et déclarez votre conteneur "Articles" dans containers/App/index.js:
import React from "react";

import Articles from "../Articles";
import Nav from "../../components/Nav";

function App() {
  return (
    <div className="App">
      <Nav />
      <Articles />
    </div>
  );
}

export default App;

Créer le conteneur "Article"

Vous pouvez voir que si vous cliquez sur l'article, il n'y a rien. Créez le conteneur d'article! Mais d'abord, vous aurez besoin de deux packages:

  • Installez react-moment et react-markdown en exécutant la commande suivante:

yarn add react-moment react-markdown moment

react-moment vous donnera la possibilité d'afficher la date de publication de votre article, et react-markdown sera utilisé pour afficher le contenu de votre article en markdown.

  • Créez un fichier ./containers/Article/index.js contenant les éléments suivants:
import React from "react";
import { useParams } from "react-router";
import Query from "../../components/Query";
import ReactMarkdown from "react-markdown";
import Moment from "react-moment";

import ARTICLE_QUERY from "../../queries/article/article";

const Article = () => {
  let { id } = useParams();
  return (
    <Query query={ARTICLE_QUERY} id={id}>
      {({ data: { article } }) => {
        const imageUrl =
          process.env.NODE_ENV !== "development"
            ? article.image.url
            : process.env.REACT_APP_BACKEND_URL + article.image.url;
        return (
          <div>
            <div
              id="banner"
              className="uk-height-medium uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light uk-padding uk-margin"
              data-src={imageUrl}
              data-srcset={imageUrl}
              data-uk-img
            >
              <h1>{article.title}</h1>
            </div>

            <div className="uk-section">
              <div className="uk-container uk-container-small">
                <ReactMarkdown source={article.content} />
                <p>
                  <Moment format="MMM Do YYYY">{article.published_at}</Moment>
                </p>
              </div>
            </div>
          </div>
        );
      }}
    </Query>
  );
};

export default Article;

Écrivez maintenant la requête pour un seul article:

  • Créez un ./src/queries/article/article.js contenant le code suivant:
import gql from "graphql-tag";

const ARTICLE_QUERY = gql`
  query Articles($id: ID!) {
    article(id: $id) {
      id
      title
      content
      image {
        url
      }
      category {
        id
        name
      }
      published_at
    }
  }
`;

export default ARTICLE_QUERY;

La page d'article est prête, il vous suffit d'ajouter ce nouveau conteneur Article dans le conteneur App. Vous allez utiliser les composants "Switch" et "Route" de react-router-dom afin d'établir un système de routage pour votre page d'article.

  • Importez et déclarez votre conteneur Article à l'intérieur de containers/App/index.js:
import React from "react";

import { Switch, Route } from "react-router-dom";

import Nav from "../../components/Nav";
import Articles from "../Articles";
import Article from "../Article";

function App() {
  return (
    <div className="App">
      <Nav />
      <Switch>
        <Route path="/" component={Articles} exact />
        <Route path="/article/:id" component={Article} exact />
      </Switch>
    </div>
  );
}

export default App;

Vous devriez maintenant pouvoir avoir accès à votre article.

Rubriques

Vous voudrez surement séparer vos articles en fonction des différentes rubriques! Alors créez ensuite une page pour chaque rubrique:

  • Créez un fichier ./containers/Category/index.js contenant les éléments suivants:
import React from "react";
import { useParams } from "react-router";
import Articles from "../../components/Articles";
import Query from "../../components/Query";
import CATEGORY_ARTICLES_QUERY from "../../queries/category/articles";

const Category = () => {
  let { id } = useParams();

  return (
    <Query query={CATEGORY_ARTICLES_QUERY} id={id}>
      {({ data: { category } }) => {
        return (
          <div>
            <div className="uk-section">
              <div className="uk-container uk-container-large">
                <h1>{category.name}</h1>
                <Articles articles={category.articles} />
              </div>
            </div>
          </div>
        );
      }}
    </Query>
  );
};

export default Category;
  • Créez un fichier ./src/queries/category/articles.js contenant les éléments suivants:
import gql from 'graphql-tag';

const CATEGORY_ARTICLES_QUERY = gql`
  query Category($id: ID!){
    category(id: $id) {
      name
      articles {
           id
        title
        content
        image {
          url
        }
        category {
          id
          name
        }
      }
    }
  }
`;

export default CATEGORY_ARTICLES_QUERY;

La page de "Rubriques" est prête, il vous suffit d'ajouter ce nouveau conteneur dans le conteneur App.

  • Importez et déclarez votre Category conteneur dans containers/App/index.js:
import React from "react";

import { Switch, Route } from "react-router-dom";

import Nav from "../../components/Nav";
import Articles from "../Articles";
import Article from "../Article";
import Category from "../Category";

function App() {
  return (
    <div className="App">
      <Nav />
      <Switch>
        <Route path="/" component={Articles} exact />
        <Route path="/article/:id" component={Article} exact />
        <Route path="/category/:id" component={Category} exact />
      </Switch>
    </div>
  );
}

export default App;

Si vous avez tout suivi et tout fait correctement, je vous félicite car vous avez terminé votre blog strapi react et devriez pouvoir l'utiliser. J'espère que vous avez apprécié ce tutoriel et que vous reviendrez bientôt pour d'autres sur Gomytech.

Retrouvez la version anglaise de cet article ici.