About meArticles

All My Articles

A better way to create event listeners in React

Mar 21st, 2024

#react

# performance

#eventlistener

#javascript

# best-practices

In JavaScript, we can write code that listens and reacts to various events using DOM event listeners. This can be easily accomplished by using the addEventListener method, which is available on any HTML element. However, in React, calling addEventListener directly on an element can cause some performance issues. In this short article, we will learn a better and more optimized way of creating event listeners in React. TL;DR: Use useRef to reference the element and add the event listener to the ref instead of adding the event listener directly to the element. It’s important to note that in this article, I used function-based components hence all the code snippets using the useRef hook. To use this approach in class-based components, you will have to create refs with createRef method.

Read More
Building a blog with React and RestDB

Apr 29th, 2022

#react

#nosql

#database

#javascript

Use RestDB to store articles and React for the front end of your blog When building apps that require a backend, we spend much time setting up a server and database, writing APIs with which the frontend can send and receive data to and from the backend. With RestDB, you can easily spin up a server and create a database. Each database collection comes with Rest API endpoints to perform CRUD operations on the database, and of course, you can add more collections. In this article, we will learn how RestDB works by building a blog app with React using RestDB to store the blog’s articles. What is RestDB? RestDB (also known as restdb.io) is a simple online NoSQL database backend with automatic APIs and low code javascript hooks. Basically, with RestDB you get a ready-to-use database with automatic APIs that you can use to perform CRUD operations on the database. RestDB completely takes away the complexity of building a server and writing endpoints for basic CRUD operations. There are many reasons why software developers should consider using RestDB. Easy to use: With RestDB, you can define the schema for your data, and add collections and descriptions for your models. It is free for teams: You can give access to people on your team, depending on their needs and access levels. With RestDB, you don’t only get a database. You can also link the database up with your web page domain easily. They are other NoSQL database backends like RestDB, like Google Firebase, Amazon DynamoDB, Azure Cosmos DB, Amazon DocumentDB, and more. These alternatives also provide easy-to-use and fully managed cloud-based databases just like RestDB with some other added features like MongoDB compatibility (Amazon DocumentDB), the option to integrate with an SQL database(Azure Cosmos DB), etc. Learn more about RestDB alternatives here: 5 Powerful Alternatives to REST APIs. Next, we will learn how to work with RestDB by building a blog app with React and connecting it to a RestDB database. Building a Blog with React and RestDB. To get started, we will clone a repo from Github. This repo contains the project’s starting files (components) and some config/setups. To do this, open your command line terminal and run the command below. git clone https://github.com/Origho-precious/RestDB-blog-starter.git After cloning, navigate into the project folder and install dependencies by running yarn install or npm install. In this project, I have already added some components and configs. We have tailwind setup for styling, react-router-dom for navigation, to render markdown styles we will be using react-markdown and two of its plugins: remark-gfm and rehype-raw. Let's quickly go over the components we have in the project. Button - This is a simple Button component with two variants. Navbar - This component shows the blog's name and a button that routes a page where we can create a post and a button to go back to the home page. PreviewPost - This component renders the body of a post with react-markdown. We will use this in a write page to preview what the article's body looks like. We also have three helper functions in src/utils/helperFunctions.js, truncateText will be used for truncating texts so they don't overflow out of their parent elements. calcReadTime calculates the read time of an article, using the number of words contained in the body of the article and a metric of 200 words per minute. convertDate converts timestamps to a particular data format using moment. Lastly, in src/page, there are three folders with index.jsx files. The files in each just render paragraphs for now, but we will update them later in this article. Next, let’s create a RestDB account, set up a database, and connect our app to it. Creating a RestDB Account Let’s navigate to the RestDB official webpage. Click on the “Get your account” button. That will take you to a page where you can signup. After signing up and verifying your account (if you don’t use the Google or Facebook signup options), You will see a page like the one below. Yay!! You have now created your RestDB account. Next, let us create a database for our blog app. To do this, click on the “Create New” button at the top-right of the page. It will pull up a modal like the one below, where we can enter the name of the database or even copy an existing database. But we will be creating a new one here. So enter what you’d like to name the database; I will name mine restblog. We just created our first RestDB database. You should see a screen like this. Click on the database name to create a collection, define a schema for the collection’s models and connect our blog with it. You will see a page like the one below, basically empty except for the sidebar and an icon at the top-right of the page. Click on that gear icon. It will enable developer mode so we can do all the things stated in the paragraph above. When you click on that icon, you should see a screen like this, I know that doesn’t look very clear, and you might want to ask why we have those things there when we’ve not created any collection in the database. When you create a database in RestDB, it auto-generates a “users” collection, and it also generates other collections for emails, etc. For this article, we won’t be handling authentication. Let’s simply add a collection for our blog’s articles. To do this, click on the “Add Collection” button. I’ll call the collection articles. Add a description as well (it's optional, though) and save. Upon saving, You will see that the collection we just created is in the list of collections. Click on it to add models to it. You should see a page like this. Here we will be adding fields (models for the collection we created). Click on the “Add Field” button to get started. You will see a screen like the one above. We will be creating four fields: title — This will be an article’s title body — The article’s content tags — Technologies used in the article e.g. react, react-router-dom, etc. it will be optional. timestamp — time the article was posted. Here is a Github gist containing what we need to create each field. If you added the fields following the table above, you should see something like this. We have now successfully created a RestDB account, created a database, a collection in that database for the blog’s articles. We also add models to the collection. What we have to do next is connect our React app with this database, so we can add, delete, or edit articles in the database. Let’s see the endpoints we can hit. RestDB provides a Swagger documentation for each database created. To access this documentation, click on the name of the database on the top of the sidebar, just beneath the search input. It will navigate us to a page like this. Click on “API tools” to open up a page like this. Click on the link under “Generate Swagger REST API” which will open up the swagger docs. You will see the endpoints autogenerated for the collections in the Swagger docs. We will need an API key to be able to access the database from our app. Go back to the Swagger docs link and click on “API Keys”, and you will see this. Click on “Manage API Keys”. You will be routed to a new page that should look like the one below. Let’s add a new API key for our project by clicking on the “Add new” button. A modal will pop up. Add a description and select the type of HTTP request we want this API key to support. As seen above, I selected GET, POST, DELETE, and PATCH. Save and copy the API key generated for you. You can see mine below. Copy the API key, and go to the project you cloned. In the root directory, create a .env file. In it, add the API key in this format, REACT_APP_API_KEY=${YOUR_API_KEY} NOTE: Do not use my API Key because I will have deleted it by the time you read this. 😂 With the API key, we can now go back to our code editor and finish up the app. Creating an Axios instance with custom configs Let’s create an axios instance with some configs. To do this, we will need to add the base URL of the endpoints we will hit, we'd also add some headers (an example: our API key) so we don't have to add them on all requests. Let's get started by installing axios with yarn add axios or npm install axios. With Axios installed, let's navigate to src/utils and add a new file, api.client.js, with the code below. import axios from "axios"; export default axios.create({ baseURL: "https://restblog-dced.restdb.io/rest", headers: { "Content-Type": "application/json", "x-apikey": process.env.REACT_APP_API_KEY, "cache-control": "no-cache", },}); We created an axios instance with a base URL and custom headers. With it, we will make all the HTTP requests we will need in this app. Building a PostForm component In this section, we will build a component with which, We can create an article and make a POST request to add it to our RestDB database. We will also be able to edit an article with this component. In the components folder inside src, create a new folder called PostForm and a file inside it PostForm.jsx and add the code below. import { useEffect, useState } from "react";import { useHistory } from "react-router-dom";import axios from "../../utils/api.client"; const PostForm = ({ state, id, setArticleBody }) => { const history = useHistory(); const [data, setData] = useState(null); const [title, setTitle] = useState(""); const [body, setBody] = useState(""); const [tags, setTags] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); useEffect(() => { if (id) { const fetchArticles = async () => { setLoading(true); try { const { data } = await axios.get(`/articles/${id}`); setData(data); setTitle(data?.title); setBody(data?.body); setArticleBody(data?.body); setTags(data?.tags); setLoading(false); } catch (error) { console.log(error); setLoading(false); } }; fetchArticles(); } }, [id, setArticleBody]); const postArticle = async () => { if ((title, body)) { setLoading(true); setError(""); try { await axios.post( "/articles", JSON.stringify({ title, body, tags, timestamp: new Date().toISOString(), }) ); return history.push("/"); } catch (error) { setLoading(false); setError("Something went wrong!"); return console.log(error); } } setError("Title and Body fields can't be empty!"); }; const editArticle = async () => { if ((title, body)) { setLoading(true); setError(""); try { await axios.patch( `/articles/${id}`, JSON.stringify({ ...data, title, body, tags, }) ); return history.push("/"); } catch (error) { setLoading(false); setError("Something went wrong!"); return console.log(error); } } setError("Title and Body fields can't be empty!"); }; const onSubmitHandler = (e) => { e.preventDefault(); if (state !== "edit") { return postArticle(); } return editArticle(); }; ... Above, we imported several dependencies, and then we created states for input and text area values using useState. We also initialized the useHistory hook to get the history object. This component has three props: state - this will either be 'add' or 'edit'. We will know if we're to edit an article or create a new one with this. id - This will be null if the state equals' edit'. If the id isn't null/undefined, we use it to fetch the details of the article we want to edit. setArticleBody - this function will send the content of the article's body to the page where this component will be used so that the PreviewPost component can use it. We added a useEffect, and inside it we are using the id prop to fetch the details of the article we want to edit by making an HTTP request with the id. We then set the values to their respective states to populate the inputs and text area with them. Next, is a function postArticle. In this function, we check if the title and body states have values. If not, we trigger an error as those fields are required to create an article. Otherwise, we make a POST request to the RestDB server sending a stringified object containing the article's title, body, tags(if any), and timestamp: all the fields we created in the database. The timestamp is set to the article's creation time, converted to ISO format. Beneath that is a function for editing an article, similar to the postArticle function, except that it makes a PATCH request to the server with the article's id. The onSubmitHandler function, is passed to a form and it calls either editArticle or postArticle function depending on the state. Let’s finish this component with the code below to render some jsx styled with tailwind. ... return ( <form onSubmit={!loading ? onSubmitHandler : () => {}} id="post-article" className="w-full" > <h2 className="mb-6 text-2xl font-bold text-center"> {state === "add" ? "Add New Blog Post" : "Edit Mode"} </h2> <div className="w-full"> <input id="title" type="text" value={title} onChange={(e) => { setError(""); setTitle(e.target.value); }} placeholder="Enter the article's title" disabled={id && loading && true} /> </div> <div className="w-full my-6"> <input id="tags" type="text" value={tags} onChange={(e) => setTags(e.target.value.trim())} placeholder="(Optional) Tags e.g javascript, typescript " disabled={id && loading && true} /> </div> <div className="w-full"> <textarea id="body" onChange={(e) => { setError(""); setBody(e.target.value); setArticleBody(e.target.value); }} value={body} placeholder="Write post content. You can use markdown syntax here" disabled={id && loading && true} /> </div> {error && <p className="text-red-600 text-xs mt-3 -mb-1">{error}</p>} </form> );}; export default PostForm; Open Source Session Replay OpenReplay is an open-source alternative to FullStory and LogRocket. It gives you full observability by replaying everything your users do on your app and showing how your stack behaves for every issue. OpenReplay is self-hosted for full control over your data. Happy debugging for modern frontend teams — start monitoring your web app for free. Building an ArticleCard component Let’s build a component that will display details of an article, handle delete functionality and route a user to the edit article page. In src/components, create a new folder ArticleCard and a file named ArticleCard.jsx inside it add the code below into the file. import { Link, useHistory } from "react-router-dom";import { calcReadTime, convertDate, truncateText,} from "../../utils/helperFunctions";import axios from "../../utils/api.client"; const ArticleCard = ({ id, title, body, timeStamp, tags, refresh }) => { const history = useHistory(); const handleDelete = async () => { const confirmed = window.confirm( "Are you sure you want to delete this article?" ); if (confirmed) { try { await axios.delete(`/articles/${id}`); refresh && refresh(); } catch (error) { console.log(error); } } }; return ( <Link to={`/article/${id}`}> <div title={title} className="flex flex-col justify-between bg-black h-48 py-10 px-12 rounded-md hover:bg-gray-900 transition-all duration-700 relative" > <div className="absolute top-4 right-6 flex justify-end"> <span className="mr-5 hover:text-white" onClick={(e) => { e.preventDefault(); handleDelete(); }} role="button" > <i className="fas fa-trash" /> </span> <span className="hover:text-white" onClick={(e) => { e.preventDefault(); history.push(`/write/${id}`); }} role="button" > <i className="fas fa-pencil-alt" /> </span> </div> <div> <h3 className="font-bold text-2xl mb-4">{truncateText(title, 37)}</h3> <div className="flex"> {tags?.map((tag, idx) => ( <p key={tag + idx} className="mr-4 opacity-80 text-white text-sm"> #{tag.trim()} </p> ))} </div> </div> <div className="flex items-center justify-between"> <p>{convertDate(timeStamp)}</p> <p>{calcReadTime(body)}</p> </div> </div> </Link> );}; export default ArticleCard; The component above has five props; id - the id of the article being rendered, needed for deleting and editing the article title, body, timeStamp, tags - properties of the article. refresh - a function that will be called whenever an article is deleted to refresh the page, thereby fetching the updated list of articles from the server. We have a function that sends a DELETE request to the server with the id to delete the article. We render the article's details, truncating the title with truncateText, and rendering the read time and date with calcReadTime and convertDate respectively. Next, we will update the write page component. Creating Articles from the App In this section, we will update the write page, so it can handle creating articles from the app with the PostForm component we created earlier. This component will also handle article editing using the same PostForm component, expecting an id param. Navigate to src/pages/write/index.jsx and replace what is there with the code below. import { useState } from "react";import { useParams } from "react-router-dom";import Button from "../../components/Button/Button";import PostForm from "../../components/PostForm/PostForm";import PreviewPost from "../../components/PreviewPost/PreviewPost"; const Write = () => { const { id } = useParams(); const [previewMode, setPreviewMode] = useState(false); const [articleBody, setArticleBody] = useState(""); return ( <div className="px-20 py-8 relative text-white bg-black w-3/5 mx-auto rounded-lg" style={{ height: "85vh", maxHeight: "600px", overflowY: "scroll" }} > <div role="button" onClick={() => setPreviewMode(!previewMode)} className="absolute right-8 top-6 hover:text-opacity-50 flex items-center duration-500 rdb-preview" style={{ color: previewMode ? "#2eff7b" : "" }} > {previewMode ? ( <p className="mr-3">Write</p> ) : ( <p className="mr-3">Preview Body</p> )} {!previewMode ? ( <i className="fas fa-eye" /> ) : ( <i className="fas fa-pencil-alt" /> )} </div> <div style={{ display: !previewMode ? "block" : "none" }}> <PostForm setArticleBody={setArticleBody} id={id} state={id ? "edit" : "add"} /> <footer className="mt-4"> <Button form="post-article" type="submit" className="mr-6"> Publish </Button> </footer> </div> <div style={{ display: previewMode ? "block" : "none" }}> <PreviewPost children={articleBody} /> </div> </div> );}; export default Write; Firstly, we imported the hooks and components we will need in this file. useParams will help us access particular segments of the page's URL. In this case, we are expecting the special segment of the URL to be an id (check src/App.js). We destructured the id from the useParams hook in the component. We have two states. One will be handling previewMode: we will use this state to toggle between showing the PostForm or PreviewPost components. The second state, articleBody, will hold the article's content, set from PostForm. We then render the content of the component. Fetching and Rendering Articles In this section, we will update src/pages/home/index.jsx file fetch articles from the server and render them using the ArticleCard component. To do this we will need the ArticleCard component, our Axios instance, useState to hold the response of the HTTP request (an array of articles) and another state for refreshing the page. Finally we have a useEffect to fetch the articles when the page is rendered or refreshed. Let's do this by replacing the file's content with the code below. import { useEffect, useState } from "react";import ArticleCard from "../../components/ArticleCard/ArticleCard";import axios from "../../utils/api.client"; const Home = () => { const [articles, setArticles] = useState([]); const [loading, setLoading] = useState(false); const [refresh, setRefresh] = useState(false); const fetchArticles = async () => { setLoading(true); try { const res = await axios.get("/articles"); setArticles(res?.data); setLoading(false); } catch (error) { console.log(error); setLoading(false); } }; useEffect(() => { fetchArticles(); }, [refresh]); return ( <section className="w-1/2 mx-auto"> {loading ? ( <p className="text-center">Loading...</p> ) : articles?.length ? ( articles?.map((article) => ( <article key={article?._id} className="mb-4"> <ArticleCard id={article?._id} title={article?.title} tags={article?.tags?.split(",")} body={article?.body} timeStamp={article?.timestamp} refresh={() => setRefresh(!refresh)} /> </article> )) ) : ( <p className="text-center">No article, create post</p> )} </section> );}; export default Home; So far, we have written some codes to create, edit and delete articles. One last thing to do is create a page to view the entire content of an article. The ArticleCard doesn't show the body/content of an article. Let's do that in the next section. Building article page Navigate to src/pages/article/index.jsx and replace the file's content with the code below. import { useEffect, useState } from "react";import { useHistory, useParams } from "react-router";import ReactMarkdown from "react-markdown";import gfm from "remark-gfm";import rehypeRaw from "rehype-raw";import axios from "../../utils/api.client";import { calcReadTime, convertDate } from "../../utils/helperFunctions"; const Article = () => { const params = useParams(); const history = useHistory(); const [loading, setLoading] = useState(false); const [article, setArticle] = useState(null); useEffect(() => { if (!params?.id) { history.push("/"); } }, [history, params]); useEffect(() => { const fetchArticle = async () => { if (params?.id) { try { setLoading(true); const res = await axios.get(`/articles`, { params: { q: { _id: params?.id, }, }, }); setArticle(res?.data[0]); setLoading(false); } catch (error) { setLoading(false); } } }; fetchArticle(); }, [params]); return ( <div className="w-4/5 mx-auto mt-16 mb-24"> {loading ? ( <p className="text-center">Loading...</p> ) : article ? ( <> <header className="rounded-md bg-black mb-10 max-w-9/12 py-12 px-20"> <h1 className="text-2xl text-center font-semibold uppercase"> {article?.title} </h1> <div className="flex items-center justify-center"> <p className="mt-4 text-sm text-center mr-8"> {convertDate(article?.timeStamp)} </p> <p className="mt-4 text-sm text-center"> {calcReadTime(article?.body)} </p> </div> </header> <> <ReactMarkdown className="prose" remarkPlugins={[gfm]} rehypePlugins={[rehypeRaw]} children={article?.body} /> </> </> ) : ( <h3>Article not found!</h3> )} </div> );}; export default Article; Above, we added code to: fetch details of an article using the article’s id (gotten from the URL of the page), render the title, tags, and the timestamp of the article properly using the necessary helper functions and render the body with react-markdown as it might contain markdown syntax. It is time to test the app. In your terminal, run yarn start or npm run start to start the dev server. You should see a screen like this. You can create, view, edit, and delete posts. Feel free to tweak the code to your preference. Conclusions We’ve now wholly built a blog app using React and RestDB, an online NoSQL database. In this article, we learned what RestDB is and how to use it by creating a RestDB account, setting up a database, adding a collection to the database, adding models, and defining a schema for them. We also learned how to generate an API key and how to generate a Swagger documentation for a RestDB database server. And finally, we were able to connect our blog app with it. There are still some more things you can learn about RestDB, handle authentication, add custom routes, use webhooks, and host pages, etc. To learn more, visit the official documentation. Resources Github Repository for project starting code Final Project Code Repository RestDB official documentation. Tailwindcss docs React-router-dom docs Originally published at https://blog.openreplay.com on April 29, 2022. Building a blog with React and RestDB was originally published in StackAnatomy on Medium, where people are continuing the conversation by highlighting and responding to this story.

Read More
Saving Netlify App Secrets using Doppler.

Oct 1st, 2021

#env

#security

#netlify

#doppler

When deploying applications on netlify, we usually add our app’s environment variables manually. And whenever there’s a need to update it, we have to go back there to netlify to do it. With Doppler, an organization/team or individuals can manage their application’s environment variables easily. In this article, we will be learning how to integrate Doppler with Netlify. Goal In this article, we will clone a mini e-commerce project built with Reactjs that uses firebase for authentication from Github, save the app’s environment variables in a doppler workspace and sync it with netlify. To achieve this, we will set up a doppler account, create a workspace, add a project to the workspace and sync it with netlify. At the end of this article, readers will know how to integrate Doppler with netlify. Prerequisites You should have a netlify account. If you don’t already, you can create one here. What is Doppler and why should I use it? Following the first two sections of this article, you might be wondering, “what exactly is doppler?”. In this section, we will briefly go over what doppler is and why you should use it. Doppler is a universal secret manager. It helps Software Engineers store/manage credentials used in their applications just like the traditional .env files. With doppler, we can share secret credentials/variables across many platforms, in several programming languages. See all the possible doppler integrations here. With Doppler, we can manage all the secret credentials/variables used in an application across different platforms in one place (a single source of truth), for example, if your company has a MERN stack app with the frontend deployed on netlify, and maybe a test version of the frontend on vercel and the backend on AWS, you can easily manage all the credentials used in all these platforms with doppler. It’s that easy and fast. Syncing Doppler with Netlify In this section, we will learn how to sync credentials saved in doppler with an app deployed on netlify. To get started, Let’s clone the project we will be deploying on netlify from Github using the code below. To do this, you need to have git installed in your machine. git clone https://github.com/Origho-precious/ecommerce-project.git Next, create a repository and add the project to it. You need to do this to deploy the project on netlify via Github. After doing that, log in to your netlify account and deploy the application there. Creating a Doppler Workspace. The next thing to do is to set up a doppler workspace, create a project for the e-commerce app, and add the env variables we need in the app. let’s do that below. When creating a doppler account, you will be prompted to create a workspace. You can add your team members to it and manage the access level each person should have in that workspace. Let’s create a doppler workspace. Let’s get started by visiting the doppler official website and creating an account. After that, we will get to a screen where we need to create a workspace as seen below. After filling and submitting the form. the workspace will be created, and we will be routed to a screen like this. That is what your workspace should be like if you create a new workspace. If you notice, there’s a test project added there already, but we won’t be using that. Let’s add a new project for the e-commerce app by clicking on the plus icon there. As seen above, I named my project firebase-commerce and added a description. Next, we need to add the environment variables needed in the project. Clicking on the project we just created will take us to a screen like the one below. There you’ll see different environments prepopulated for us, development, staging, and production. We can add different environment variables needed in each environment. And if they all use the same variables, we can easily add them to one and sync them across all environments. Note that we can also add custom environments by clicking on the hamburger icon at the top right of the page. Let’s add variables to the development environment, and also sync them to the two others. To do this, we need to click on the rectangle with dev in it. It will open a page like the one below. We can add variables singly by clicking on the ‘Add first Secret’ or by clicking on the other button and where we import all our variables from ENV, JSON, or YAML format. We will use the second option to make things faster. Click on the button. You should see a screen like the one below. Copy and paste the below code into the textarea provided and click on ‘Import Secrets` below. REACT_APP_APIKEY = AIzaSyBzklmuZsb_5Ait1FatkT-Mg3Vor1hFJ8A REACT_APP_AUTH_DOMAIN = ecomerce-project-40990.firebaseapp.com REACT_APP_DATABASE_URL = https://ecomerce-project-40990.firebaseio.com REACT_APP_PROJECT_ID = ecomerce-project-40990 REACT_APP_STORAGE_BUCKET = ecomerce-project-40990.appspot.com REACT_APP_SENDER_ID = 361284578530 REACT_APP_APP_ID = 1=361284578530:web:58896ab84048601b9682bb Importing it will take us back to this screen with all the variables set up. There’s a ‘Save’ button at the top right of the page, click on it to save the variables. I’m selecting the two other environments do they will have the environment variables also. We have now set up a doppler account, a workspace, and a project. We also variables to environments in the project. Next, let’s add a netlify integration to this project. to do this click on ‘Integrations’. Now, let’s add a netlify integration by clicking on the ‘Add Integration’ button. then select netlify We will be routed to a page where we need to authorize netlify to use doppler Next, we select the website needed from the list of sites we have deployed to netlify. At this point, If you are yet to deploy the e-commerce project to netlify, you need to do it now to continue. As seen above, we will also select the config we want to use from the environments we have in the project e.g development, staging, and production. I will go with development (dev). The last input is for selecting which variables should be used in cases where we have variables from doppler and netlify. I set my preference to doppler. When you're done, click on the button below. We have now integrated the project we deployed on netlify with our secrets from doppler. To verify that the variables on the doppler workspace are correctly integrated with the netlify app, go to the project on netlify and check the environment variables. You can see mine below. You can go ahead and test the app if you want using the netlify site link. Conclusion We have now learned how to save secrets in doppler and integrate them with Netlify. While learning to do this, we learned how to create a doppler workspace and how to add environment variables/secrets. We did this and were also able to confirm they were added correctly to the project on netlify. Now you see how easy and fast is it to manage netlify app secrets with doppler, you will see more of the advantages when you want to update any of the variables. We can do that in the doppler workspace and save it, any platform integrated with that workspace will be updated accordingly. Resources for More Learning Intro to Doppler Doppler Integration with Netlify Documentation Originally published at https://origho-precious.hashnode.dev.

Read More
Using Recoil instead of Redux For State Management In React Applications

Sep 16th, 2021

#front-end-development

#programming

#redux

#javascript

#react

A simple alternative, the same powerful features Among all the state management libraries available for use in React apps, Redux is the most popular even ahead of React’s Context APIs. There are also other awesome state management libraries used in React apps one of which is Recoil. Recoil unlike Redux is very easy to set up, even easier to set up than the new Redux toolkit library. In this article, we will learn how to use Recoil to manage states in React apps instead of Redux. What is Recoil? According to documentation, Recoil is a state management library for React applications. Recoil is an open-source state management library with more than 14k stars on Github, it was invented by Dave McCabe, a Software Engineer at Facebook. It provides a global state so all components in a React application can share states easily and it is minimal compared to Redux with no boilerplate code setup needed. Recoil provides a data-graph that flows from shared states into React components. The two core concepts of Recoil according to the official documentation are: Atoms, which are units of the global state provided by Recoil, components can access and subscribe to changes made to them. Selectors with which we can transform states either synchronously or asynchronously, and components can also access and subscribe to. Why Use Recoil? Considering that we have many other state management libraries out there and also React’s Context API and component state, why then should we use Recoil in our React apps?. Let’s highlight some of the reasons below: Recoil just like Redux provides a global state. With Recoil, we won’t have to pass states as props down to children components in order to share them between components (a concept known as prop drilling). Once we hook up a component to any Atom or Selector, they are subscribed to it, so any update made to that piece of state will be reflected across the app to wherever it’s being used. With Recoil Selectors, we can transform a state synchronously or asynchronously and use the derived state anywhere in our app. Recoil is minimal and requires no boilerplate code to get started. Redux is very popular but many developers still frown at it because of the amount of code they need to write to set it up. Building a React App with Recoil We have now gone over what Recoil is, its core concepts, and why you should consider using it. In this section, we will build an anime-quote-generator, this app will fetch quotes from an external API based on selected animes. Let’s get started by generating a new React app with the command below. npx create-react-app anime-quote-generator After that, open it in your favorite code editor. Next, we will install Recoil and get started building our app components. Run the command below to install Recoil. yarn add recoil OR npm install recoil Let’s configure our app to use Recoil. Navigate to src/index.js, here, we only need to wrap our entire app with RecoilRoot; a Recoil component. Let's do that below. https://medium.com/media/628d6dd0da6723a2962bedfc8b56b47c/hrefWe have successfully set up Recoil in our React app just by wrapping all our app’s components with it. You see how easy the setup is, to do this using Redux we will have to write some lines of code to create a store before wrapping our app with the React-Redux Provider component that will contain the store. Now that we have set up Recoil in our app, let’s start building components, pages, and sharing states with Recoil. Building AnimePill Component This component will render the title of an anime passed to it, and when clicked, it will route us to a page where we’ll see quotes from that anime. First, we need to install react-router-dom for routing between pages in our app and styled-components for styling. Let’s do that with the command below: yarn add react-router-dom styled-components OR npm install react-router-dom styled-components Next, let’s create a folder in the src folder, called components. In the components folder, create a folder called AnimePills and a file called AnimePills.jsx inside that folder. The path to this file from src should be src/components/AnimePills/AnimePills.jsx, now add the code below to that file. https://medium.com/media/f2a1038de78261f823c1bed25336da01/hrefAbove, we just created a component called AnimePills. This component takes in 2 props; anime and color, with the anime we will construct a link using the Link component from react-router-dom and we will use the color as a background-color. We then style the component with styled-components. Building Quote and SmallQuote components We will be building 2 components in this section. Let’s start with the Quote component. Inside our components folder, create a new folder called Quote and a file Quote.jsx inside it. In this component, we will simply render a quote from Naruto and style the component with styled-components. Add the code below to the file. https://medium.com/media/d97165930b244bf12ad264e3ca76791e/hrefNext, let’s create the SmallQuote component. This component expects 3 props (anime, character, and quote), we will render these props, and style the component with styled-components. To do this, create a folder inside src/components called SmallQuote, inside it create a file SmallQuote.jsx and add the code below https://medium.com/media/50579d17e6c22ad07830cda22244156c/hrefAbove, we just built a component called SmallQuote and styled it with styled-components. It is very similar to Quote component, the purpose of splitting them is to make the code easier to understand. So if you want to make the Quote component reusable to include features of the SmallQuote component, feel free to do that. Next, we will be building our app atoms and selector. Building Our App Global State (Atoms and Selector). To get started, navigate into our src folder and create a folder called store, inside this folder create a file called index.js. In this file, we will build all the atoms we need and also a selector to modify one of the atoms. Let's start with the first atom, animeTitles. Add the code below to create our first atom. https://medium.com/media/76ed3b0656c0d715841bfb4f1c5198d6/hrefAbove, we created an Atom by importing atom from recoil and called it " animeTitles. We then defined the required properties of an atom, which are key - this should be a unique ID among other atoms and selectors we will create in the app. default - this is the default value of the atom. Doing this with Redux, we will have to create an action creator with a specific type, the action creator will return the type and a payload passed to it, and also we will create a reducer to update our redux store. but with Recoil we don’t need to handle all of that, with the key prop, Recoil knows the part of the global state to update so when we pass data to update the state it does it correctly and we won't need to compare action types as we would do in Redux. Following the same pattern, let’s create another atom called animePageNum. we will use this atom to hold page number, this will help us properly handle pagination in this app. Add the code below to this file. https://medium.com/media/6ae3a3910230940fbc0e160ef3358313/hrefNext, let’s create a selector to mutate the array of data we will have in the animeTitles atom by slicing the array to return only 50 items at a time based on the page number which we will get from animePageNum atom. https://medium.com/media/87bd3ab6ac2f84fb94fabf406eb04feb/hrefAbove, we created a selector called slicedAnimeTitles, we defined a key property just like we did in the atoms we created above, and here we have a new property get whose value is a function, this is only available in selectors, this function has 2 parameters but here we are using just one of them that is get with which we can access the value of an atom or selector. Inside this function, with the get method, we saved the animeTitles and animeListPageNum atoms into 2 variables animes and pageNum respectively, and with the pageNum we specified the index to start slicing from and then returned a new array of just 50 items. We have now successfully created all the shared states we will be using in this app. Next. Let’s create a pagination component, to handle user click and update the animeListPageNum state (atom) so we can update the list of animes we are returning from the selector we just created. Building Pagination Component To begin, navigate to src/components and create a new folder Pagination, inside create a file Pagination.jsx, paste the code below into this file. https://medium.com/media/0a0c7740d36b6192699de3c336d0d31c/hrefAbove, we created a new component Pagination. This component has a prop listLength; this will help us determine the page numbers to render. We then imported [useRecoilState](https://recoiljs.org/docs/api-reference/core/useRecoilState), which accepts a state as an argument just like React's useState hook, This also works similar to useSelector in Redux But here we can update the state directly and not have to dispatch an action. We can access the value of the state passed to useRecoilState and also update the state, We also created a component state with useState hook to hold an array of numbers, these will be the page numbers to render in this component. https://medium.com/media/c76a6de8ae3495ded91f622398caa1f1/hrefIn the useEffect we imported above, we created an array of numbers with the listLength prop, and updated the numArr state with the array we created and then we looped through the array of nums and rendered them in buttons, each button will update the animeListPageNum when clicked. Let's complete this component by adding the code below. https://medium.com/media/dfc8c540c2f83d4bffb26f060abae32c/hrefWith the Pagination component done, we can now build our app pages and complete the app. Building Homepage Component In this section, we will build our homepage component, this page will render a static quote and also a list of animes using the AnimePill component we created earlier and also the Pagination component for pagination. To do this, in our src folder let's create a folder called pages, in this folder create a folder called home and a file inside it called index.jsx, folder path should src/pages/home/index.jsx. Add the code below to this file https://medium.com/media/a4ea1eac555f9d0682eefcd438ee3302/hrefAbove, we imported: useRecoilValue from the Recoil library to get the state values, styled from styled-components to style the Homepage component, AnimePill to render anime title, Pagination to handle pagination, Quote to display a static anime quote, SlicedAnimeTitles is the selector we created earlier. We will be its return value on this page, and animeTitles which is the first atom we created to hold the list of animes. Next, we created a function component called Homepage inside this component, we accessed the animeTitles and the slicedAnimeTitles state using useRecoilvalue and also we created an array of colors (we will pass these colors to the AnimePill component at random). We then created a function generateColor, this component returns a random color from the colors array. After that, we returned the component body styled with styled-components, a header, the Quote component, and a little notice telling a user what to do, then if we have animes, we will loop through the slicedAnimes and render each of them with the AnimePill component by passing the anime to the component and also a color prop from the generateColor function and if there's none we render a 'no data' state. Next, we are checking to see if the length of the animes state is more than 50, if true we render the Pagination component. and finally, we added a block of styled-component styles We’ve now successfully created our Homepage component, in the next section let's create a page we will be routed to when we click on any AnimePill. In that component, we will make an API call to the external API and fetch all quotes from the selected anime and render the quotes. Building Animepage Component Let’s get started by navigating to our pages folder, inside create a folder called anime and a file inside it called index.jsx. Add the code below to the file. https://medium.com/media/c2303f29817d7b9a309bad7d704b4afe/hrefAbove, you’ll notice that we didn’t use Recoil, instead, we saved the response we got from the API request in a useState, this is because the states will only be used in this component. Open Source Session Replay Debugging a web application in production may be challenging and time-consuming. OpenReplay is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue. It’s like having your browser’s inspector open while looking over your user’s shoulder. OpenReplay is the only open-source alternative currently available. Happy debugging, for modern frontend teams — Start monitoring your web app for free. Creating App Routes and Fetching Animes To complete this app, Let’s navigate to src/App.js. Here, we will be doing 2 things: Fetch a list of animes from the external API and updating the animeTitles atom we created earlier with it. Define our app routes with react-router-dom. Let’s get started. Go to src/App.js and replace what we have there with the code below. https://medium.com/media/03c9bbfcf4a6f4cd12725165769a3314/hrefAbove, We imported useEffect - We will be making our API call inside it, so that we can fetch the array of anime once the page is rendered. BrowserRouter, Route, and Switch from react-router-dom - We will create our routes with them. [useSetRecoilState](https://recoiljs.org/docs/api-reference/core/useSetRecoilState) from recoil - with this, we will update the animeTitles atom just by passing the atom to it as an argument, and axios - for fetching data from the external API Next, we will create the App component and fetch the animes inside. To do that add the code below. https://medium.com/media/7f34819f50dcd159dbaff392ff4c9806/hrefAbove, we created the App component, and inside we created a variable setTitles with which we will update our animeTitles atom (state). Next, we created an async function called fetchAnimes, inside it, we fetched the animes from the external API using axios and updated our animeTitles state with it while using try-catch for error handling. After that we called the fetchAnimes inside the useEffect we imported so this function runs once the page is rendered. Let’s finish up the App component by adding routes. https://medium.com/media/966e8739c2da89d79f5e0a362fed264d/hrefWe have now completed our app. let’s start our dev server to see how it works. Run the command below in your terminal yarn start OR npm start If you followed along correctly, you should see these pages. Click on any anime and see a page like this. I will click on Naruto. Conclusion In this article, we learned what Recoil is, why use it, and how to use it instead of Redux by building an anime-quote-generator app using Recoil for state management. We also compared how to do certain things in Recoil to Redux, and we saw how easy it is to use Recoil. You can learn more about Recoil from the official docs. Resources Github repository for tutorial project Recoil Official documentation Redux Official documention List of Some React State Management libraries Originally published at https://blog.openreplay.com on September 16, 2021. Using Recoil instead of Redux For State Management In React Applications was originally published in StackAnatomy on Medium, where people are continuing the conversation by highlighting and responding to this story.

Read More
Getting Started with React Cosmos

Aug 23rd, 2021

#programming

#javascript

#react

#reactjs

#testing

Everything you ever wanted to know but were afraid to ask about React Cosmos As React developers, we break complex components into smaller bits to reduce complexity and also to make testing easier. React Cosmos further reduces that complexity by giving us a sandbox to easily test, see and iterate quickly while building these components. React Cosmos is a library that provides a sandbox environment for developing and testing React components in Isolation. Think of it like a library that provides a way to isolate components and be able to see what they look like (their UI), make changes, and iterate quickly. In the sandbox, we can change props and see our components reflex the changes instantly. It only supports CRA and Nextjs officially, It also supports the use of Typescript. The only requirements to use react cosmos are React 16.8 (or newer) Node 10 (or newer). Why Use React Cosmos There are many ways to test component UIs and some testing frameworks help us achieve that, to mention but a few react-testing-library, where we write tests to check what a component has, for example, if we are testing a form component, we will write tests to check if a button is rendered, if there are inputs and/or select tags, etc and we usually see the results in our terminals but with React cosmos, we have a visual way to test our components (Visual TDD) which makes testing easier. React cosmos also comes with hot-reload so we can see changes made to our components in the sandbox instantly, and it provides a medium for quick testing with prop changes and state changes right there in the cosmos explorer. Getting Started with React cosmos Now that we have an overview of React cosmos, let’s see how to work with it by testing components of a food ordering app (no checkout & authentication) with it in isolation. To get started, we will clone the food ordering app from here. You can do that by running the command below in your terminal (make sure you have git installed in your machine). git clone https://github.com/Origho-precious/cosmos-food.git After cloning the repository, navigate into the project folder and open it up in your favorite code editor. In this project, we are using tailwind for styling, and react-router-dom for routing. Install project dependencies by running yarn install or npm install in your terminal. Let’s quickly go over the components we have in this project. In the src/components folder, we have 4 components: Button - a simple button component CartCard - is used to show details of a cart item, and we can also update cart item quantity from this component. Checkout - shows a summary of the cart (sub-total price, delivery fee, and total price). FoodCard - shows food details and a button to add food to the cart. And in the src/pages, we have 2 components, these are the 2 pages in the app. cart - this component renders all cart items and the checkout component home - this is the app's landing page, it primarily renders food items and a navbar. Now let’s start the app to see what it looks like. Start your dev server with yarn start OR npm start You should see these on your browser. In the next section, we will start testing components in this app with React cosmos. Using React Cosmos Let’s install the React cosmos package with the command below. yarn add react-cosmos -D To use react cosmos with create-react-app, we need to add and change a few things. Firstly, create a cosmos config file, In our project root folder, create a file called cosmos.config.json, inside it add the code block below { "staticPath": "public", "watchDirs": ["src"], "webpack": { "configPath": "react-scripts/config/webpack.config" }, "globalImports": ["src/styles/main.css"]} We are telling cosmos to watch the src folder and watch out for static assets in our public folder, we are also pointing cosmos to where it should get our webpack config file from, and finally, we added our CSS import as seen above. The next step is to add a package that makes cosmos work well with create-react-app, without this we will run into an issue with cosmos and create-react-app hot-reload. learn more about it here. Run the command below in your terminal yarn add cross-env -D Let’s update our package.json file, to include cosmos scripts "scripts": { "start": "npm run watch:css && react-scripts start", "build": "npm run watch:css && react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "watch:css": "postcss src/styles/tailwind.css -o src/styles/main.css", "cosmos": "cross-env FAST_REFRESH=false cosmos", "cosmos:export": "cross-env FAST_REFRESH=false cosmos-export" } Start our cosmos server with yarn cosmos OR npm cosmos After the server starts, go to http://localhost/5000 in your browser, you should see this. If you see any error in your terminal, please go through the steps again. Open Source Session Replay Debugging a web application in production may be challenging and time-consuming. OpenReplay is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue. It’s like having your browser’s inspector open while looking over your user’s shoulder. OpenReplay is the only open-source alternative currently available. Happy debugging, for modern frontend teams — Start monitoring your web app for free. Writing Fixtures I know you might be wondering what fixtures are, don’t sweat it. Fixtures are files containing default export of your React Components or React Node that will be shown in React cosmos explorer/sandbox. There are two options to creating fixtures files are to end with .fixture.{js,jsx,ts,tsx} e.g Button.fixture.js or Create a folder inside src called __fixtures__ to house all your fixtures inside it like __fixtures/Button.jsx. We will be using the second option to keep things a bit more organized. Let’s create our first fixture, Button Fixture Inside src create a folder called __fixture__ inside create a file called Button.jsx. We are going to create a Button fixture with the code below: import Button from "../components/Button/Button"; export default ( <div className="w-60 mx-auto"> <Button>Cosmos</Button> </div>); First, we imported the component we want to test We exported it as default, notice the div and classes, I did that to resize the width of the button and center it horizontally. Go to your Cosmos explorer, you should see this Notice the Button looking exactly like it is in our app, and the children prop we passed showing there. On the right panel, we can directly update the prop passed to the button component, play around with it and see how it changes immediately, To further test the Button’s UI, let’s add a variant prop so we will have a primary and secondary Button variant. Go to src/components/Button/Button.jsx and update it to look like this const Button = ({ children, variant = "primary" }) => { return ( <button className={`block w-full h-12 ${ variant === 'primary' ? "bg-black" : "bg-blue-600" } hover:opacity-70 mt-3 text-sm rounded-sm`} style={{ color: '#fff', border: "none", outline: "none" }} type="button" > {children} </button> );}; export default Button; We just updated our Button component to have a prop called variant which updates the background color of the Button. Now to go src/__fixtures__/Button.jsx and update it to look like this import { useSelect } from 'react-cosmos/fixture';import Button from "../components/Button/Button"; export default () => { const [variant] = useSelect('variant', { options: ['primary', 'secondary'], }); return ( <div className="w-60 mx-auto"> <Button variant={variant}>Cosmos</Button> </div>)}; Above we updated our Button fixture to include a variant prop as we did the Button component and also we introduce a Control panel hook useSelect, with this hook we are able to set options of the variant prop, so in our sandbox, we can select from the options we have other than typing it manually. There's also another control panel hook React cosmos offers useValues with it, we can update data like count, etc Let’s see the Button component in the explorer. On the right, you can select either of the two variant options to change the variant prop and see the background-color change accordingly. We have now successfully created a Button fixture and tested it in our Cosmos sandbox (explorer). Let’s continue by creating a Checkout fixture. Checkout Fixture Just like we created the Button fixture, in src/__fixtures__/ create a new file called Checkout.jsx and add the code below import Checkout from "../components/Checkout/Checkout"; const data = { subTotal: 100, deliveryFee: 5, total: 105,}; export default ( <div className="w-60 mx-auto"> <Checkout subTotal={data.subTotal} deliveryFee={data.deliveryFee} total={data.total} /> </div>); Above we created a fixture for our Checkout component using mock data. Let's check what it looks like in our Cosmos sandbox, Click on it on the left panel. It should look like this Simple right? Now you can test it by passing different prop values to it. or play with it in the explorer. Cards Fixture Here, we will create a different type of fixture called Multi fixture, It's like the regular fixture but here, we can create more than one fixture from the same file. It's easier than it sounds, let's do it below to see how that works. Create a file called Cards.js in the __fixtures__ folder and add the following code import CartCard from "../components/CartCard/CartCard";import FoodCard from "../components/FoodCard/FoodCard"; const food = { id: 1, name: "Peppered Chicken", imgURL: "https://sisijemimah.com/wp-content/uploads/2015/07/image70.jpg", price: "8.00",}; const order = { id: 1, name: "Peppered Chicken", imgURL: "https://sisijemimah.com/wp-content/uploads/2015/07/image70.jpg", price: "8.00", qty: 1, updateList: () => {},}; export default { FoodCard: ( <FoodCard id={food.id} name={food.name} price={food.price} imgURL={food.imgURL} /> ), CartCard: ( <CartCard id={order.id} name={order.name} price={order.price} imgURL={order.imgURL} qty={order.qty} updateList={order.updateList} /> ),}; Above we imported, FoodCard and CartCard components and created two objects to contain mock data for the FoodCard and CartCard components and passed them to the respective components as props. Let’s see what a multi fixture looks like in our cosmos sandbox, You see now we have a Cards fixture and in it, we have FoodCard and CartCard components, and we can click on them to see them. It's more organized now right? Yeah, that's how you can organize your sandbox as it gets larger. Lastly, let us build a Page fixture — A multi-fixture for pages (home and cart pages). we will do that below. Pages Fixture Create a new file in__fixtures__ called Pages.js add the code below import Cart from "../pages/cart";import Home from "../pages/home"; export default { cart: <Cart />, home: <Home />}; A very simple fixture to show what a whole page looks like, They should look like this in our sandbox; We now have home and cart page fixtures, click on any of the cart icons on the FoodCard to add to the cart and navigate to the cart page to see what you add. You can also update the quantity of the items ordered on the CartCard and see the values update accordingly as well as the checkout values. We can visually test our app now, we see how it functions by testing the components in isolation and testing how they work together also in isolation without starting our app’s dev server. This is the visual TDD React cosmos offers. Other than writing tests for every component and checking the results in our terminal, with React cosmos, we can see the component working instead. Decorators help us wrap fixtures with some shared properties like CSS styles. To create a decorator we just need to create a cosmos.decorator.js file in the same folder as the fixtures we want to be wrapped with that decorator. Let's create a decorator for all our pages, to just change the background color a bit. In src/__fixtures__/ create a file called cosmos.decorator.js and add the code below. export default ({ children }) => ( <div className="bg-gray-100 h-screen">{children}</div>); We just wrapped our fixtures with a gray background color and made the page height 100vh. We have now successfully wrapped our fixtures with a decorator. Go over to the cosmos explorer to see the change. Extending Responsiveness We can specify the viewports we want in our sandbox, specifying the devices as well as their height and width. Let do that below Goto src/cosmos.config.json, update the file to look like this { "staticPath": "public", "watchDirs": ["src"], "webpack": { "configPath": "react-scripts/config/webpack.config" }, "globalImports": ["src/styles/main.css"], "ui": { "responsivePreview": { "devices": [ { "label": "iPhone 5", "width": 320, "height": 568 }, { "label": "iPhone 6", "width": 375, "height": 667 }, { "label": "iPhone 6 Plus", "width": 414, "height": 736 }, { "label": "Medium", "width": 1024, "height": 768 }, { "label": "Large", "width": 1440, "height": 900 }, { "label": "1080p", "width": 1920, "height": 1080 } ] } }} Now restart the cosmos server for it to reflect and go over the sandbox. On the top right, we have 4 icons. Click on the second from the left, you can now toggle the different viewports we just passed to it. Static Export We can export the fixtures we created if we want to host it as a component library with any static hosting service like netlify. Simply run the cosmos:export command yarn cosmos:export OR npm run cosmos:export Conclusion We have now completely tested our components using react cosmos and we have a component library running alongside our app with which we can quickly test components and we can add more fixtures as we keep building the app. In this tutorial, we built a food ordering service and testing all the components using React cosmos to learn how it works. Resources Tutorial Project Live Link — https://cosmos-foods.netlify.app/ Github link to the complete tutorial project — https://github.com/Origho-precious/cosmos-food master branch. To learn more about React cosmos check out their official docs — https://github.com/react-cosmos/react-cosmos/tree/main/docs Originally published at https://blog.openreplay.com on August 23, 2021. Getting Started with React Cosmos was originally published in StackAnatomy on Medium, where people are continuing the conversation by highlighting and responding to this story.

Read More