<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gerald</title>
    <description>The latest articles on DEV Community by Gerald (@geraldmaboshe).</description>
    <link>https://dev.to/geraldmaboshe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F210567%2F9125ef34-f37d-4733-98df-977d316ac0df.png</url>
      <title>DEV Community: Gerald</title>
      <link>https://dev.to/geraldmaboshe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geraldmaboshe"/>
    <language>en</language>
    <item>
      <title>Build a Fullstack App With Strapi and Next.js</title>
      <dc:creator>Gerald</dc:creator>
      <pubDate>Sun, 14 Feb 2021 18:35:29 +0000</pubDate>
      <link>https://dev.to/geraldmaboshe/build-a-fullstack-app-with-strapi-and-next-js-5d8p</link>
      <guid>https://dev.to/geraldmaboshe/build-a-fullstack-app-with-strapi-and-next-js-5d8p</guid>
      <description>&lt;p&gt;Let's build a fullstack blog using &lt;a href="https://strapi.io/" rel="noopener noreferrer"&gt;Strapi&lt;/a&gt; and &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;. &lt;br&gt;
This article is based on &lt;a href="https://www.youtube.com/watch?v=WrmndNpWSJw" rel="noopener noreferrer"&gt;Digital Ocean's Tech Talk by Chris Sev&lt;/a&gt;.&lt;br&gt;
To get the ball rolling, let's setup our Strapi backend by running the following command in the terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-strapi-app blog-strapi --quickstart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a Strapi project named &lt;em&gt;blog-strapi&lt;/em&gt; and automatically opens the admin panel in our default browser.&lt;br&gt;
Let's go ahead and enter credentials and click &lt;em&gt;LET'S START&lt;/em&gt;. We should see the Strapi dashboard as shown below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84qkgm3ax39hdxdwz932.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84qkgm3ax39hdxdwz932.PNG" alt="Alt Text" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's create our collection. On the dashboard, click on &lt;em&gt;CREATE YOUR YOUR FIRST CONTENT-TYPE&lt;/em&gt;. Let's have &lt;em&gt;Post&lt;/em&gt; as display name and click &lt;em&gt;Continue&lt;/em&gt;. Select &lt;em&gt;Text&lt;/em&gt; as the collection type and name the field &lt;em&gt;title&lt;/em&gt; and leave the &lt;em&gt;Short text type&lt;/em&gt; selected. Click on &lt;em&gt;Add another field&lt;/em&gt; and select &lt;em&gt;Text&lt;/em&gt; collection type and name it &lt;em&gt;slug&lt;/em&gt;. Let's add one more field by clicking &lt;em&gt;Add another field&lt;/em&gt;,  select &lt;em&gt;Rich text&lt;/em&gt; and name it &lt;em&gt;content&lt;/em&gt; and click &lt;em&gt;finish&lt;/em&gt; and &lt;em&gt;save&lt;/em&gt;. Our collection now looks as below&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwmzxfs11vqok6rwgmblt.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwmzxfs11vqok6rwgmblt.PNG" alt="Alt Text" width="738" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create posts, go to the left panel under Collection types, click on &lt;em&gt;Posts&lt;/em&gt; and hit the &lt;em&gt;Add New Posts&lt;/em&gt; button. Let's add the title as &lt;em&gt;My Wins This Week&lt;/em&gt;, slug as &lt;em&gt;my-wins-this-week&lt;/em&gt;, content as &lt;em&gt;Won the golf tournament&lt;/em&gt; and click &lt;em&gt;save&lt;/em&gt; and &lt;em&gt;publish&lt;/em&gt;. Head over to the browser at  &lt;a href="http://localhost:1337/posts" rel="noopener noreferrer"&gt;http://localhost:1337/posts&lt;/a&gt;. We should be getting a Forbidden error because the API is secured by default. To change that, let's get back to the Strapi dashboard and click on &lt;em&gt;settings&lt;/em&gt;. Under &lt;em&gt;USERS AND PERMISSIONS PLUGIN&lt;/em&gt;, click on &lt;em&gt;Roles&lt;/em&gt; then public and select &lt;em&gt;find&lt;/em&gt;, &lt;em&gt;findone&lt;/em&gt;, &lt;em&gt;create&lt;/em&gt; and click &lt;em&gt;save&lt;/em&gt;. Let's get back to our browser and refresh &lt;a href="http://localhost:1337/posts" rel="noopener noreferrer"&gt;http://localhost:1337/posts&lt;/a&gt;. We should see our post as shown below&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwfcwik2e9b60x8no2icb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwfcwik2e9b60x8no2icb.PNG" alt="Alt Text" width="556" height="452"&gt;&lt;/a&gt;&lt;br&gt;
Our post looks good so far but we have no idea who the author is. To be able to add an author, we need to add another field of type relation to the Post collection type. On the Strapi dashboard, click on &lt;em&gt;Content-Type Builder&lt;/em&gt;, select &lt;em&gt;Post&lt;/em&gt;, click on &lt;em&gt;Add another field&lt;/em&gt; and select &lt;em&gt;Relation&lt;/em&gt;. On the &lt;em&gt;File&lt;/em&gt; dropdown select &lt;em&gt;User(from-users-permiss...)&lt;/em&gt; and select a &lt;em&gt;User has many Posts&lt;/em&gt; relation. Let's rename &lt;em&gt;users_permissions_user field name&lt;/em&gt; to simply &lt;em&gt;user&lt;/em&gt; and click &lt;em&gt;finish&lt;/em&gt; and &lt;em&gt;save&lt;/em&gt;.&lt;br&gt;
Let's go ahead and create a user. Under collection types, select &lt;em&gt;Users&lt;/em&gt; and click on &lt;em&gt;Add New Users&lt;/em&gt;. Input user credentials and toggle &lt;em&gt;Confirmed&lt;/em&gt; button to set it to ON. Under &lt;em&gt;Posts(0)&lt;/em&gt;, let's assign &lt;em&gt;My Wins This Week&lt;/em&gt; post to this user(in my case daka) because why not? Click save and refresh the browser at &lt;a href="http://localhost:1337/posts" rel="noopener noreferrer"&gt;http://localhost:1337/posts&lt;/a&gt;. You should see the user object included in our response as shown below &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiqp75902wf08cawbji2y.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiqp75902wf08cawbji2y.PNG" alt="Alt Text" width="568" height="771"&gt;&lt;/a&gt;&lt;br&gt;
Go ahead and create a couple of more posts and assign them users so that we have enough data to work with on the frontend.&lt;/p&gt;

&lt;p&gt;Let's create our Next.js frontend by running the following command in the terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app blog-next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command creates a new Next.js app. Once the setup is done, run the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd blog-next
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start our Next.js app server and the app can be accessed at &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;.&lt;br&gt;
Let's open up our app in a Text Editor(I'm using VS Code), go to &lt;code&gt;index.js&lt;/code&gt; and replace everything in the return block with &lt;code&gt;&amp;lt;div&amp;gt;We are here!&amp;lt;/div&amp;gt;&lt;/code&gt; and save. Head over to the browser at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; and we should see the output as shown below&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb6nsq3rf78mx178rtg14.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb6nsq3rf78mx178rtg14.PNG" alt="Alt Text" width="323" height="112"&gt;&lt;/a&gt;&lt;br&gt;
Let's go above the Home component and get our API data using &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation" rel="noopener noreferrer"&gt;getStaticProps&lt;/a&gt; function as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export async function getStaticProps() {
  //get posts from API
  const res = await fetch('http://localhost:1337/posts');
  const posts = await res.json();

  return {
    props: { posts }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in our Home component we can receive the posts as props and loop over them as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Home({ posts }) {
  return (
    &amp;lt;div className={styles.container}&amp;gt;
      {/* Loop over posts and show them */}
      {posts &amp;amp;&amp;amp;
        posts.map(post =&amp;gt; (
          &amp;lt;div key={post.id} className={styles.post}&amp;gt;
            &amp;lt;h1&amp;gt;{post.title}&amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;{post.content}&amp;lt;/p&amp;gt;
            &amp;lt;em&amp;gt;By {post.user.username}&amp;lt;/em&amp;gt;
          &amp;lt;/div&amp;gt;
        ))}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's also add a bit of styling. In the &lt;code&gt;styles&lt;/code&gt; directory, go to  &lt;code&gt;Home.module.css&lt;/code&gt; and replace all that is in there with the CSS code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.container {
  display: grid;
  grid-template-columns: auto auto auto;
  margin: 5%;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.post {
  padding-bottom: 10%;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we save this, we should see the posts as shown below(of course you could do better styling).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgqxmtodi3io5ha4yd7bf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgqxmtodi3io5ha4yd7bf.PNG" alt="Alt Text" width="800" height="259"&gt;&lt;/a&gt;&lt;br&gt;
Now let's handle routing by creating a file called &lt;code&gt;[slug].js&lt;/code&gt; in the pages directory. This is a way that Next.js dynamically generates a bunch of files. There are two main things we need to do in &lt;code&gt;[slug].js&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tell Next.js how many pages there are and&lt;/li&gt;
&lt;li&gt;For each individual page; get the data for that page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can achieve these with the help of &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation" rel="noopener noreferrer"&gt;getStaticPaths&lt;/a&gt; and &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation" rel="noopener noreferrer"&gt;getStaticProps&lt;/a&gt; functions respectively as shown in the snippet below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Tell Next.js how many pages there are
export async function getStaticPaths() {
  const res = await fetch('http://localhost:1337/posts');
  const posts = await res.json();

  const paths = posts.map(post =&amp;gt; ({
    params: { slug: post.slug }
  }));

  return {
    paths,
    fallback: false
  };
}

//For each individual page; get the data for that page
export async function getStaticProps({ params }) {
  const { slug } = params;
  const res = await fetch(`http://localhost:1337/posts?slug=${slug}`);
  const data = await res.json();
  const post = data[0];
  return {
    props: { post }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required" rel="noopener noreferrer"&gt;&lt;code&gt;fallback&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;getStaticPaths&lt;/code&gt; is set to false because we have a small number of paths to pre-render - so they are all statically generated during build time. In &lt;code&gt;getStaticProps&lt;/code&gt;, &lt;code&gt;const post&lt;/code&gt; is assigned &lt;code&gt;data[0]&lt;/code&gt; because the response we get is an array and we are only interested in the first element.&lt;/p&gt;

&lt;p&gt;We can now add a Post component in &lt;code&gt;[slug].js&lt;/code&gt; and pass the props as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Post({ post }) {
  return &amp;lt;div&amp;gt;{post.title}&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we route to &lt;a href="http://localhost:3000/my-wins-this-week" rel="noopener noreferrer"&gt;http://localhost:3000/my-wins-this-week&lt;/a&gt;, we get a single post as shown below:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuhlheg0u6mryiwjju5o5.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuhlheg0u6mryiwjju5o5.PNG" alt="Alt Text" width="464" height="151"&gt;&lt;/a&gt;&lt;br&gt;
Awesome right?&lt;/p&gt;

&lt;p&gt;So, to be able to generate our post files, we need to add the following script to our &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "export": "next build &amp;amp;&amp;amp; next export"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's stop the server and run it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run export
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates HTML files from all the posts we have in Strapi.&lt;br&gt;
These files are in the &lt;code&gt;out&lt;/code&gt; folder and are minified and ready to be hosted on a static server.&lt;br&gt;
Now we will add provision to navigate between the posts page and the single post page using the Next.js &lt;code&gt;Link&lt;/code&gt;. Edit the return block of the Home component as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className={styles.container}&amp;gt;
      {/* Loop over posts and show them */}
      {posts &amp;amp;&amp;amp;
        posts.map(post =&amp;gt; (
          &amp;lt;Link href={`/${post.slug}`} key={post.id} className={styles.post}&amp;gt;
            &amp;lt;a&amp;gt;
              &amp;lt;h1&amp;gt;{post.title}&amp;lt;/h1&amp;gt;
              &amp;lt;p&amp;gt;{post.content}&amp;lt;/p&amp;gt;
              &amp;lt;em&amp;gt;By {post.user.username}&amp;lt;/em&amp;gt;
            &amp;lt;/a&amp;gt;
          &amp;lt;/Link&amp;gt;
        ))}
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the return block for the Post component in&lt;code&gt;[slug].js&lt;/code&gt; as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;div&amp;gt;
      &amp;lt;Link href="/"&amp;gt;
        &amp;lt;a&amp;gt;Home&amp;lt;/a&amp;gt;
      &amp;lt;/Link&amp;gt;
      &amp;lt;h1&amp;gt;{post.title}&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to import &lt;code&gt;Link&lt;/code&gt; from "next/link" in both cases.&lt;br&gt;
Now, when we start the server, we should be able to navigate through our site.&lt;/p&gt;

&lt;p&gt;The last thing we want to  do is creating a post. For that we need an API exploration tool, in my case I'm using &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;. Let's create a POST request with the following body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "title": "The New Normal",
    "slug": "the-new-normal",
    "content": "The new normal is here",
    "user": {
        "id": 1
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we hit send, below is the post response we are getting&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2huviavem3ut9gbvshdq.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2huviavem3ut9gbvshdq.PNG" alt="Alt Text" width="800" height="418"&gt;&lt;/a&gt;&lt;br&gt;
When we head over to our Strapi dashboard, we can see our new post added to the list of posts and when we click on it, we see the information passed as shown below.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc30rcb89c0apkmsuhoo3.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc30rcb89c0apkmsuhoo3.PNG" alt="Alt Text" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it, our basic fullstack app is done. &lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How To Use Redux with Hooks in a React-TypeScript Project</title>
      <dc:creator>Gerald</dc:creator>
      <pubDate>Fri, 18 Sep 2020 11:57:46 +0000</pubDate>
      <link>https://dev.to/geraldmaboshe/how-to-use-redux-with-hooks-in-a-react-typescript-project-4j50</link>
      <guid>https://dev.to/geraldmaboshe/how-to-use-redux-with-hooks-in-a-react-typescript-project-4j50</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt; is a predictable state container for JavaScript applications. In this tutorial, I will show you how to use redux to manage state in &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; with &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TyepeScript&lt;/a&gt; and &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;Hooks&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;If you are only interested in viewing complete code on GitHub, click &lt;a href="https://github.com/geraldmaboshe/posts-redux-tutorial" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Otherwise, let's setup the project using &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;. In this tutorial I will be using yarn but you should be fine with npm as well. In your terminal run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app posts --typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a React Typescript project called posts. To start the development server and view the project in your browser, run the following commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd posts
yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installations
&lt;/h3&gt;

&lt;p&gt;To use redux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @reduxjs/toolkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use Redux with React and TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react-redux
yarn add @types/react-redux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To add redux thunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add redux-thunk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To add redux devtools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add redux-devtools-extension
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Redux
&lt;/h3&gt;

&lt;p&gt;Setup your redux folder as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src
-redux
--actions
--effects
--interfaces
--reducers
--store
--types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interfaces folder is used for adding all interfaces that can be used across the project. For this tutorial, we will use posts fake data from &lt;a href="https://jsonplaceholder.typicode.com/" rel="noopener noreferrer"&gt;JSONPlaceholder&lt;/a&gt;. In interfaces directory, create a file called &lt;em&gt;Post.ts&lt;/em&gt; and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interface above defines a single &lt;a href="https://jsonplaceholder.typicode.com/posts" rel="noopener noreferrer"&gt;post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to setup our types. In the types folder, create a file called &lt;em&gt;PostTypes.ts&lt;/em&gt; and add the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Post } from '../interfaces/Post';

export const GET_POSTS = 'GET_POSTS';

export interface GetPostsStateType {
  posts: Post[];
}

interface GetPostsActionType {
  type: typeof GET_POSTS;
  payload: Post[];
}
export type PostActionTypes = GetPostsActionType;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;GetPostsStateType&lt;/em&gt; interface is defining what the state will look like; an array of posts. &lt;em&gt;GetPostsActionType&lt;/em&gt; interface is defining the action type that you will see later in this tutorial.&lt;/p&gt;

&lt;p&gt;In the reducers directory, create a file called &lt;em&gt;PostReducer.ts&lt;/em&gt; and add the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  GET_POSTS,
  GetPostsStateType,
  PostActionTypes
} from '../types/PostTypes';

const initialStateGetPosts: GetPostsStateType = {
  posts: []
};

export const getPostsReducer = (
  state = initialStateGetPosts,
  action: PostActionTypes
): GetPostsStateType =&amp;gt; {
  switch (action.type) {
    case GET_POSTS:
      return {
        ...state,
        posts: action.payload
      };
    default:
      return state;
  }
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, we initialize state of type &lt;em&gt;GetPostsStateType&lt;/em&gt; that we defined earlier. We then create a reducer function called &lt;em&gt;getPostsReducer&lt;/em&gt;. A reducer takes two parameters; state and action. In our case, state and action are of types &lt;em&gt;initialStateGetPosts&lt;/em&gt; and &lt;em&gt;PostActionTypes&lt;/em&gt; respectively while the reducer function returns &lt;em&gt;GetPostsStateType&lt;/em&gt;. In the switch block, if the case is &lt;em&gt;GET_POSTS&lt;/em&gt;, we return whatever is there in the state and update it with the new payload and the default case is state. Note that in a bigger project there would be a lot of cases.&lt;/p&gt;

&lt;p&gt;Create another file in the reducers folder and lets call it &lt;em&gt;index.ts&lt;/em&gt;. In here, we will combine all our reducers using &lt;em&gt;combineReducers&lt;/em&gt; and export them as &lt;em&gt;rootReducer&lt;/em&gt;[You can call it anything really] as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { combineReducers } from 'redux';
import { getPostsReducer } from './PostReducer';

const rootReducer = combineReducers({
  posts: getPostsReducer
});

export default rootReducer;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will create our store. A store holds the whole state tree of the application. In the store folder, let's have &lt;em&gt;index.ts&lt;/em&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers';
import { composeWithDevTools } from 'redux-devtools-extension';

const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(thunkMiddleware))
);

export type AppState = ReturnType&amp;lt;typeof rootReducer&amp;gt;;
export default store;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we are doing in here is creating a store from the combined reducers called &lt;em&gt;rootReducer&lt;/em&gt;. &lt;em&gt;composeWithDevTools&lt;/em&gt; will allow you to monitor global state in your browser if you've installed the &lt;a href="https://github.com/reduxjs/redux-devtools" rel="noopener noreferrer"&gt;Redux Devtools Extension&lt;/a&gt;. &lt;em&gt;applyMiddleware(thunkMiddleware)&lt;/em&gt; allows us to dispatch &lt;a href="https://redux.js.org/glossary#async-action" rel="noopener noreferrer"&gt;async actions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make the store available to React components, in src/index.ts, we wrap &lt;em&gt;App&lt;/em&gt; in &lt;em&gt;Provider&lt;/em&gt; and pass the store as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/Provider&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you should see your global state with an empty array of posts as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbjwxmopoojd9lcc3i4ek.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbjwxmopoojd9lcc3i4ek.PNG" alt="Initial State" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only way to change the state in the store is through an action dispatch. In the actions folder create &lt;em&gt;PostActions.ts&lt;/em&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { GET_POSTS, PostActionTypes } from '../types/PostTypes';
import { Post } from '../interfaces/Post';

export const getPostsAction = (posts: Post[]): PostActionTypes =&amp;gt; {
  return {
    type: GET_POSTS,
    payload: posts
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;getPostsAction&lt;/em&gt; function accepts an array of posts and returns a type of &lt;em&gt;GET_POSTS&lt;/em&gt; and posts data passed to the payload variable. Note that type and payload can be given names of your choice.&lt;/p&gt;

&lt;p&gt;To fetch our posts from the fake API, let's create &lt;em&gt;Posts.ts&lt;/em&gt; in the effects folder and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { getPostsAction } from '../actions/PostActions';
import { Dispatch } from 'redux';
import { PostActionTypes } from '../types/PostTypes';
export const getPosts = () =&amp;gt; {
  return function (dispatch: Dispatch&amp;lt;PostActionTypes&amp;gt;) {
    const POST_URL = 'https://jsonplaceholder.typicode.com/posts';
    fetch(POST_URL, {
      method: 'GET'
    })
      .then(res =&amp;gt; res.json())
      .then(data =&amp;gt; {
        dispatch(getPostsAction(data));
        return data;
      });
  };
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we are doing here is dispatching the &lt;em&gt;getPostsAction&lt;/em&gt; and passing it the data from the fake API. &lt;/p&gt;

&lt;h3&gt;
  
  
  React Component
&lt;/h3&gt;

&lt;p&gt;Finally, in &lt;em&gt;App.ts&lt;/em&gt;, we can access our App State. Update &lt;em&gt;App.ts&lt;/em&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from './redux/effects/Posts';
import { Post } from './redux/interfaces/Post';
import { AppState } from './redux/store';

export default function Posts() {
  const dispatch = useDispatch();
  useEffect(() =&amp;gt; {
    dispatch(getPosts());
  }, [dispatch]);
  const posts = useSelector((state: AppState) =&amp;gt; state.posts);
  const postItems = posts.posts.map((post: Post) =&amp;gt; (
    &amp;lt;div key={post.id}&amp;gt;
      &amp;lt;h1&amp;gt;{post.title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{post.body}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  ));
  return &amp;lt;div&amp;gt;{postItems}&amp;lt;/div&amp;gt;;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, we bring in &lt;em&gt;useDispatch&lt;/em&gt; and &lt;em&gt;useSelector&lt;/em&gt; from &lt;em&gt;react-redux&lt;/em&gt;. The &lt;em&gt;useDispatch&lt;/em&gt; hook is used to dispatch actions as needed. In our case, we are passing the &lt;em&gt;getPosts&lt;/em&gt; effect to dispatch in the &lt;em&gt;useEffect&lt;/em&gt; hook. This will add the data coming from the fake API to our redux store as soon as the App component mounts. At this point your redux store should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnpo0akc1d15g1s1eh5ar.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnpo0akc1d15g1s1eh5ar.PNG" alt="Posts State" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;useSelector&lt;/em&gt; works more or less like &lt;a href="https://react-redux.js.org/using-react-redux/connect-mapstate" rel="noopener noreferrer"&gt;mapStateToProps&lt;/a&gt; when using &lt;a href="https://react-redux.js.org/api/connect" rel="noopener noreferrer"&gt;connect&lt;/a&gt;. It allows us to access app state in a React functional component. In our case we are interested in getting posts from the posts state and that is exactly why we are iterating through &lt;em&gt;posts.posts&lt;/em&gt;. Then we display the post title with &lt;em&gt;post.title&lt;/em&gt; and body with &lt;em&gt;post.body&lt;/em&gt;. Interesting right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;There are many ways you could use redux in your React project. Go with a setup that works for you. Redux can have a lot of boilerplate but comes in handy once the boilerplate code is out of the way.&lt;/p&gt;

&lt;p&gt;Happy coding! &lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>typescript</category>
      <category>hooks</category>
    </item>
  </channel>
</rss>
