<?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: Carl-W</title>
    <description>The latest articles on DEV Community by Carl-W (@ugglr).</description>
    <link>https://dev.to/ugglr</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%2F69865%2F2461f253-f232-48aa-a0bf-d983c2501079.jpg</url>
      <title>DEV Community: Carl-W</title>
      <link>https://dev.to/ugglr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ugglr"/>
    <language>en</language>
    <item>
      <title>Ghost Jobs: 30% of What You're Applying to Doesn't Exist</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Mon, 13 Apr 2026 21:24:16 +0000</pubDate>
      <link>https://dev.to/remoet/ghost-jobs-30-of-what-youre-applying-to-doesnt-exist-ka</link>
      <guid>https://dev.to/remoet/ghost-jobs-30-of-what-youre-applying-to-doesnt-exist-ka</guid>
      <description>&lt;p&gt;You applied to 100 jobs last month. About 30 of them didn't exist.&lt;/p&gt;

&lt;p&gt;Not "the role was filled." Not "they went with an internal candidate." The job was never real. Nobody was ever going to get hired. The posting was there to serve a purpose that had nothing to do with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers are worse than you think
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.entrepreneur.com/business-news/one-quarter-of-jobs-posted-online-are-fake-ghost-jobs-study/496683" rel="noopener noreferrer"&gt;27.4% of U.S. LinkedIn listings&lt;/a&gt; are ghost jobs. A &lt;a href="https://www.resumebuilder.com/3-in-10-companies-currently-have-fake-job-postings-listed/" rel="noopener noreferrer"&gt;Resume Builder survey&lt;/a&gt; found 3 in 10 companies have fake job postings live right now. Not by accident. On purpose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mintcareer.ai/ghost-jobs-guide" rel="noopener noreferrer"&gt;81% of recruiters&lt;/a&gt; admit their employer posts roles that don't exist or are already filled. In tech, &lt;a href="https://mintcareer.ai/ghost-jobs-guide" rel="noopener noreferrer"&gt;40% of companies&lt;/a&gt; posted fake jobs in the past year. 79% of those are still up.&lt;/p&gt;

&lt;p&gt;Los Angeles has a &lt;a href="https://blog.theinterviewguys.com/ghost-jobs-exposed/" rel="noopener noreferrer"&gt;30.5% ghost job rate&lt;/a&gt;. But it's not a local thing. It's everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why companies do this
&lt;/h2&gt;

&lt;p&gt;The reasons are almost never about hiring. That's the part that should piss you off.&lt;/p&gt;

&lt;p&gt;Companies post jobs to look like they're growing. If you're raising a Series B and your careers page shows 40 open roles, investors see scale. Whether those roles are real doesn't matter. The perception is the product.&lt;/p&gt;

&lt;p&gt;Some companies post jobs to do free market research. They want to see who applies, what salary expectations look like, how deep the talent pool goes in a given city. You spend 45 minutes on your application. They get a data point. Nobody was ever going to call you.&lt;/p&gt;

&lt;p&gt;Others use ghost postings as a retention tool. "Look at all these open roles. We could replace you tomorrow." It's a threat dressed up as a careers page.&lt;/p&gt;

&lt;p&gt;And then there's plain negligence. A role gets filled internally. Nobody turns off the auto-renew in the ATS. The posting sits there for 6 months collecting applications from people who think it's real. This is probably the most common one, and somehow it's also the most insulting. They couldn't even be bothered to click "close."&lt;/p&gt;

&lt;h2&gt;
  
  
  15 hours you're not getting back
&lt;/h2&gt;

&lt;p&gt;Each application takes about 30 minutes when you actually do it right. Reading the description, adjusting your resume, writing responses, submitting. Apply to 100 jobs in a month, 30% are ghosts, that's 30 wasted applications. 15 hours. Gone.&lt;/p&gt;

&lt;p&gt;But the time isn't the worst part.&lt;/p&gt;

&lt;p&gt;You applied. You were qualified. You heard nothing. And you start wondering if you're the problem. Maybe your resume sucks. Maybe you need to learn another framework. Maybe you're too expensive. You internalize the rejection when there was nothing to be rejected from.&lt;/p&gt;

&lt;p&gt;The job didn't exist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsletter.jobsearch.guide/p/how-job-search-works-in-2026-and" rel="noopener noreferrer"&gt;72% of job seekers&lt;/a&gt; report negative mental health impacts from drawn-out hiring processes. Ghost jobs are a huge part of that. Every fake listing adds another false data point to your "maybe I'm not good enough" story.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to spot them
&lt;/h2&gt;

&lt;p&gt;None of these are guaranteed. But stacking them together filters out most of the garbage.&lt;/p&gt;

&lt;p&gt;Check the posting date. If it's been up for 60+ days, especially at a tech company, something is off. Most real positions fill within 30-45 days. Three months? Either it's a ghost, the role is impossibly niche, or the company can't get their act together. None of those are encouraging.&lt;/p&gt;

&lt;p&gt;Read the actual description. Ghost jobs are almost always vague. "Looking for a talented engineer to join our growing team." No tech stack mentioned. No team name. No specific project. Real hiring managers get specific because they need a specific person. Vagueness is a tell.&lt;/p&gt;

&lt;p&gt;Look at the company's pulse. Are they active on social media? Have they made recent hires you can see on LinkedIn? Do they have an engineering blog that's been updated this year? A company listing 20 open roles with zero public activity for 4 months is suspicious.&lt;/p&gt;

&lt;p&gt;Cross-reference the source. If a job shows up on Indeed, LinkedIn, Glassdoor, and three other boards but isn't on the company's own careers page, it's a stale aggregation. Some distribution service is auto-syndicating a dead listing that nobody bothered to kill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job boards won't fix this
&lt;/h2&gt;

&lt;p&gt;Job boards make money from listings. More listings means more page views. More page views means more ad revenue or higher subscription fees. A ghost job and a real job generate the same engagement metrics.&lt;/p&gt;

&lt;p&gt;Indeed, LinkedIn, Glassdoor. None of them have an incentive to remove ghost postings. The ghost job is doing exactly what their business model needs. Just not what you need.&lt;/p&gt;

&lt;p&gt;The platforms you trust to help you find work are economically rewarded for keeping fake listings live. That's a broken foundation and no amount of UI polish fixes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regulation is coming, slowly
&lt;/h2&gt;

&lt;p&gt;Ontario &lt;a href="https://www.ontario.ca/document/your-guide-employment-standards-act/written-information-publicly-advertised-job-posting" rel="noopener noreferrer"&gt;passed legislation&lt;/a&gt; requiring companies to disclose whether a posting is for a real, active vacancy. The U.S. has the &lt;a href="https://www.congress.gov/bill/118th-congress/senate-bill/4956" rel="noopener noreferrer"&gt;TJAAA bill&lt;/a&gt; working through Congress with similar requirements.&lt;/p&gt;

&lt;p&gt;When lawmakers write bills specifically about fake job postings, the problem has gone past "industry nuisance" into "systemic failure." But regulation is slow. Enforcement is slower. You can't wait for Congress to fix your job search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop searching for jobs. Start tracking companies.
&lt;/h2&gt;

&lt;p&gt;Sounds backwards. But think about it.&lt;/p&gt;

&lt;p&gt;The ghost job problem exists because you're interacting with listings, not companies. A listing can be fake. A company can't fake its existence, its tech stack, or whether it's actually made hires recently.&lt;/p&gt;

&lt;p&gt;Pick 10-20 companies where your tech stack genuinely overlaps. Track them. Watch for new roles at those specific companies. When one of them posts something, you know it's more likely to be real because you've been watching the company, not a random feed of disconnected listings.&lt;/p&gt;

&lt;p&gt;This is what I built &lt;a href="https://www.remoet.dev" rel="noopener noreferrer"&gt;Remoet&lt;/a&gt; around. 725+ remote tech companies, tracked, with real tech stack data. You star the ones that match your skills, and your &lt;a href="https://www.remoet.dev/blog/how-to-set-up-mcp-server-claude-cursor-windsurf" rel="noopener noreferrer"&gt;AI agent&lt;/a&gt; monitors them for you. It doesn't eliminate ghost jobs entirely. Some companies will always play games. But you go from fishing in a pool that's 30% fake to watching a handful of companies you've already vetted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply fewer. Apply better.
&lt;/h2&gt;

&lt;p&gt;The instinct when you learn about ghost jobs is to compensate with volume. "If 30% are fake, I'll just apply to 3x as many." That's the trap. More volume means more time wasted on ghosts, more silence, more false rejections eating at your confidence.&lt;/p&gt;

&lt;p&gt;The opposite works. Narrow your target. Verify the company is real and active. Check the posting date. Look at the tech stack. Then apply once, with effort, to something that's actually there.&lt;/p&gt;

&lt;p&gt;30% of what you're applying to doesn't exist. The fix isn't applying harder. It's not applying to bullshit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a ghost job?
&lt;/h3&gt;

&lt;p&gt;A ghost job is a posting for a position that isn't actually open or that the company never intends to fill. It exists for other reasons: signaling growth to investors, collecting market data, pressuring existing employees, or just negligence where nobody closed the listing after the role was filled internally.&lt;/p&gt;

&lt;h3&gt;
  
  
  How common are ghost jobs?
&lt;/h3&gt;

&lt;p&gt;Between 27-30% of job listings, depending on the study. Resume Builder found 3 in 10 companies currently have fake postings live. In tech specifically, 40% of companies posted at least one fake job in the past year, and 79% of those are still active.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I know if a job posting is fake?
&lt;/h3&gt;

&lt;p&gt;Look for a combination of red flags: the posting has been up for 60+ days, the description is vague with no specific tech stack or team, the same listing appears on aggregator sites but not on the company's own careers page, and the company shows no other signs of active hiring (no recent LinkedIn hires, no social media activity).&lt;/p&gt;

&lt;h3&gt;
  
  
  Are ghost jobs illegal?
&lt;/h3&gt;

&lt;p&gt;In most places, not yet. Ontario passed legislation requiring disclosure of whether a posting is for an active vacancy. The U.S. has the TJAAA bill in Congress. Regulation is moving, but slowly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why don't job boards remove ghost jobs?
&lt;/h3&gt;

&lt;p&gt;Because ghost jobs make them money. A fake listing generates the same page views, ad impressions, and engagement metrics as a real one. The platforms have no economic reason to clean them up.&lt;/p&gt;

</description>
      <category>career</category>
      <category>jobsearch</category>
      <category>remotework</category>
      <category>hiring</category>
    </item>
    <item>
      <title>What Is MCP (Model Context Protocol)? A Practical Guide</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Wed, 25 Mar 2026 11:21:58 +0000</pubDate>
      <link>https://dev.to/remoet/what-is-mcp-model-context-protocol-a-practical-guide-1i9k</link>
      <guid>https://dev.to/remoet/what-is-mcp-model-context-protocol-a-practical-guide-1i9k</guid>
      <description>&lt;p&gt;MCP (Model Context Protocol) is an open standard that lets AI agents connect to external software, discover available tools, and take actions on your behalf. Instead of being trapped in a chat window, your AI can search databases, manage projects, update profiles, and interact with any service that runs an MCP server.&lt;/p&gt;

&lt;p&gt;You've probably seen MCP mentioned everywhere lately. Twitter threads, blog posts, product announcements. Every AI company seems to be shipping an "MCP server" and every developer tool is adding "MCP support." But if you've tried to figure out what MCP actually is, you've probably run into a wall of jargon and protocol specs.&lt;/p&gt;

&lt;p&gt;I'm going to cut through that.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP in Plain English
&lt;/h2&gt;

&lt;p&gt;Anthropic introduced MCP in November 2024. In December 2025, they donated it to the Agentic AI Foundation under the Linux Foundation, with OpenAI, Block, and others as co-stewards. It's a genuinely open protocol now.&lt;/p&gt;

&lt;p&gt;Here's the problem it solves. When you use Claude or ChatGPT, the AI can talk to you, but it can't actually &lt;em&gt;do&lt;/em&gt; anything outside that conversation. It can't check your calendar, search a database, file a bug report, or look up your job applications. It's stuck inside a text box.&lt;/p&gt;

&lt;p&gt;MCP changes that. It's a universal plug that lets an AI agent reach into other software and take actions on your behalf. Search a job board. Update a project. Star a company. Send a message. Whatever the connected service supports.&lt;/p&gt;

&lt;p&gt;Yeah, I know, the USB analogy is the cliche everyone uses for MCP. But it's accurate, so I'll use it anyway: before USB, every device had its own proprietary connector. Printers, keyboards, cameras, all different cables. USB standardized the physical connection. MCP standardizes the AI-to-software connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;Under the hood, MCP uses JSON-RPC 2.0 as its wire protocol. If you've worked with LSP (Language Server Protocol), the architecture will feel familiar. There are two sides to every MCP connection:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The client&lt;/strong&gt; is your AI agent. Claude Desktop, Cursor, Windsurf, Claude Code, Cline. These are the apps where you type prompts and have conversations. They speak MCP natively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The server&lt;/strong&gt; is whatever tool or service you want the agent to access. A GitHub MCP server lets your agent manage repos and issues. A Notion MCP server lets it read and write documents. A &lt;a href="https://www.remoet.dev" rel="noopener noreferrer"&gt;Remoet&lt;/a&gt; MCP server lets it search remote job listings, manage your developer profile, and track applications.&lt;/p&gt;

&lt;p&gt;When a client connects to a server, the server advertises its capabilities through three primitives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Actions the agent can execute. Searching listings, creating a profile entry, submitting an application. These are the most commonly used primitive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt;: Data the agent can read, like files, database records, or configuration. Think of these as GET endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt;: Predefined templates that guide the agent through specific workflows. Less common but useful for complex multi-step tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each tool has a name, a description, and a JSON Schema defining its inputs. The AI reads those descriptions and figures out which tools to call based on what you ask.&lt;/p&gt;

&lt;p&gt;So when you say "find me remote companies hiring React developers," the agent looks at the available tools, picks the search tool, fills in the right parameters, calls it, and returns the results. You never have to know the tool exists. You just describe what you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP vs Function Calling
&lt;/h2&gt;

&lt;p&gt;This is the confusion I see most often. Function calling is a model-level feature where the AI can output structured JSON to invoke predefined functions. It's been around since 2023. MCP is the transport and discovery layer that sits on top of function calling.&lt;/p&gt;

&lt;p&gt;Think of it this way: function calling is the engine. MCP is the road network.&lt;/p&gt;

&lt;p&gt;Without MCP, every developer has to manually define function schemas, wire them up to API clients, handle authentication, and build the plumbing for each integration from scratch. MCP standardizes all of that. The server describes its tools once, any MCP client can discover and use them, and the client's function calling capability handles the actual invocation.&lt;/p&gt;

&lt;p&gt;So they're complementary, not competing. Function calling is what lets the model decide to call a tool. MCP is what lets the model &lt;em&gt;discover&lt;/em&gt; tools dynamically from external servers and execute them over a standardized transport.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP vs A2A (Agent-to-Agent Protocol)
&lt;/h2&gt;

&lt;p&gt;Google released their Agent-to-Agent (A2A) protocol in early 2025, and I keep seeing people ask whether it competes with MCP. Short answer: no. They solve different problems.&lt;/p&gt;

&lt;p&gt;MCP connects an agent to tools and data. A2A connects an agent to another agent. MCP is about giving one agent hands to interact with software. A2A is about letting multiple agents collaborate with each other on a task. You'd likely use both in a mature agentic system, with MCP for tool access and A2A for multi-agent coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Primitives in Practice
&lt;/h2&gt;

&lt;p&gt;I mentioned Tools, Resources, and Prompts above, but it's worth seeing how they play out in a real MCP server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.remoet.dev" rel="noopener noreferrer"&gt;Remoet&lt;/a&gt; has 38 MCP tools. When your agent connects, it receives all 38 tool definitions with their descriptions and parameter schemas. The agent doesn't need documentation. It reads the tool descriptions and figures out the right calls.&lt;/p&gt;

&lt;p&gt;Ask "find companies using Go and Kubernetes" and the agent picks the search tool. Ask "show my applications" and it picks the applications tool. Ask "update my summary" and it picks the profile update tool. All from the same conversational interface. No menus, no navigation, no context switching.&lt;/p&gt;

&lt;p&gt;This is fundamentally different from a traditional API integration. With an API, a developer writes code to call specific endpoints with specific parameters. With MCP, you describe your intent in natural language and the AI handles the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security: OAuth 2.1, PKCE, and Prompt Injection
&lt;/h2&gt;

&lt;p&gt;I won't sugarcoat this: connecting AI agents to live services introduces real security considerations.&lt;/p&gt;

&lt;p&gt;On the authentication side, MCP supports OAuth 2.1 with PKCE (Proof Key for Code Exchange). This is the same security standard used by major web applications. Each connection requires explicit user authorization, and you can revoke access at any time. Remoet's MCP implementation enforces PKCE on every authorization, with session limits and LRU eviction to prevent resource exhaustion.&lt;/p&gt;

&lt;p&gt;The trickier risk is prompt injection. If an MCP server returns malicious content in tool results, it could theoretically trick the agent into taking unintended actions. Good MCP implementations mitigate this by treating all tool results as untrusted data (Remoet's server description explicitly instructs agents to do this), but it's an active area of research. The MCP spec itself is evolving to add better guardrails here.&lt;/p&gt;

&lt;p&gt;If you're evaluating MCP servers, look for ones that use OAuth 2.1 rather than just API keys, enforce PKCE, and document their approach to prompt injection defense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Supports MCP Today
&lt;/h2&gt;

&lt;p&gt;The ecosystem has grown fast. Thousands of MCP servers are now listed across various directories, and the number is climbing weekly.&lt;/p&gt;

&lt;p&gt;On the client side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Desktop&lt;/strong&gt; and &lt;strong&gt;Claude Web&lt;/strong&gt; have native MCP support, including custom connectors via OAuth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; supports MCP servers out of the box via the CLI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor&lt;/strong&gt; has built-in MCP configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windsurf&lt;/strong&gt; supports MCP servers in its settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Code&lt;/strong&gt; now has native MCP support through GitHub Copilot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cline&lt;/strong&gt; and &lt;strong&gt;Continue&lt;/strong&gt; also support MCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the server side, the ecosystem spans every category:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Development&lt;/td&gt;
&lt;td&gt;GitHub, Linear, Sentry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Productivity&lt;/td&gt;
&lt;td&gt;Notion, Slack, Google Drive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data&lt;/td&gt;
&lt;td&gt;Supabase, PostgreSQL, various database connectors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search&lt;/td&gt;
&lt;td&gt;Brave Search, Context7 (documentation search)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Career &amp;amp; Jobs&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.remoet.dev" rel="noopener noreferrer"&gt;Remoet&lt;/a&gt; (remote job search, profile management, applications)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;td&gt;n8n, Zapier&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What's striking is that MCP servers aren't just developer tools anymore. They're showing up in every vertical: job platforms, finance tools, CRM systems, e-commerce. Any software with an API can become an MCP server, and increasingly, they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters For You
&lt;/h2&gt;

&lt;p&gt;If you're a developer, MCP means you can automate a huge chunk of your workflow through conversation. Instead of context-switching between 15 browser tabs, you tell your agent what you need and it handles the tool-hopping.&lt;/p&gt;

&lt;p&gt;If you're job hunting, this is where it gets genuinely interesting. Traditional job boards make you do all the work: search, filter, scroll, click into each listing, apply one by one. An MCP-connected job platform flips that. You tell your agent "find companies using my tech stack that are actively hiring" and it does the searching, filtering, and shortlisting for you.&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;a href="https://www.remoet.dev" rel="noopener noreferrer"&gt;Remoet&lt;/a&gt; does. Connect your AI agent once, and it handles the rest: finding companies that match your stack, tracking applications, messaging hiring teams. Your agent becomes your career assistant.&lt;/p&gt;

&lt;p&gt;But beyond any single platform, the bigger shift is this: software is becoming conversational. Instead of learning each app's UI, you describe what you want and your agent navigates the tools for you. MCP is what makes that possible at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If you want to try MCP yourself, the setup is simpler than you'd expect. Most MCP-compatible AI apps let you add servers through a configuration file or settings page. You typically need an API key or OAuth authorization from the service you want to connect, and then you're up and running.&lt;/p&gt;

&lt;p&gt;We've got a detailed setup guide covering Claude Desktop, Claude Code, Cursor, and Windsurf in our post on &lt;a href="https://www.remoet.dev/blog/how-to-set-up-mcp-server-claude-cursor-windsurf" rel="noopener noreferrer"&gt;how to set up MCP servers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a complete walkthrough of what AI-powered job search looks like in practice, check out our &lt;a href="https://www.remoet.dev/blog/ai-agent-job-search-workflow-complete-guide" rel="noopener noreferrer"&gt;agent job search guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is MCP only for Claude?
&lt;/h3&gt;

&lt;p&gt;No. MCP is an open protocol governed by the Linux Foundation. While Anthropic created it, it's been adopted by Claude, Cursor, Windsurf, VS Code, Cline, Continue, and others. Any AI client can implement MCP support. OpenAI added MCP support to their agents SDK in early 2025.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to be a developer to use MCP?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. Some setups require editing a JSON config file, which is a bit technical. But Claude Web supports custom MCP connectors through a point-and-click OAuth flow that requires zero coding. Desktop Extensions are also making one-click installs possible. The trend is clearly toward making MCP accessible to everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is MCP secure?
&lt;/h3&gt;

&lt;p&gt;MCP supports OAuth 2.1 with PKCE for authentication, which is the same security standard used by major web applications. Each connection requires explicit authorization. You control which services your agent can access and can revoke access at any time. The main emerging concern is prompt injection through tool results, which is an active area of research in the MCP community.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between MCP and a browser extension or plugin?
&lt;/h3&gt;

&lt;p&gt;Browser extensions and plugins are specific to one application. A Chrome extension only works in Chrome. A ChatGPT plugin only worked in ChatGPT (and OpenAI deprecated them). MCP is standardized across all compatible AI clients. Build one MCP server and it works with Claude, Cursor, Windsurf, VS Code, and any future client that supports the protocol. Build once, work everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many MCP servers can I connect at once?
&lt;/h3&gt;

&lt;p&gt;There's no hard protocol limit. You can connect as many MCP servers as your AI client supports. Most people connect 3 to 10 servers depending on their workflow, covering things like code management, documentation, search, and whatever domain-specific tools they need.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>claude</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Why Companies Area Restrict Jobs, Even if They Are Remote</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Thu, 29 Feb 2024 16:39:45 +0000</pubDate>
      <link>https://dev.to/ugglr/why-companies-area-restrict-jobs-even-if-they-are-remote-35lo</link>
      <guid>https://dev.to/ugglr/why-companies-area-restrict-jobs-even-if-they-are-remote-35lo</guid>
      <description>&lt;p&gt;Currently, remote work is becoming more mainstream than ever, especially for software engineers who actually only need a computer and a stable internet connection to perform their duties, the fact that companies restrict jobs to geographic areas might seem weird. &lt;/p&gt;

&lt;p&gt;Why would it matter where you are if your work and contributions are happening over the internet? This question is often discussed by software engineers looking for remote positions with mostly eye-rolling 🙄 and ridicule. However, there are very valid reasons for this from the company's point of view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuc06y0z94gw2w0b2zyvm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuc06y0z94gw2w0b2zyvm.gif" alt="wait what" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Navigating the maze of taxation and legalities
&lt;/h3&gt;

&lt;p&gt;The primary hurdle for companies employing internationally is the legal complexity. Different countries have unique employment laws, tax regulations, and social security requirements. For a company based in one country, ensuring compliance across all these different jurisdictions can be a logistical nightmare. This complexity isn't just about following the law; it's also about the significant administrative burden involved in managing these requirements for employees in multiple countries. For software engineers, this means that despite the borderless nature of their work, the legal borders significantly impact where they can be employed even if they are remote.&lt;/p&gt;

&lt;p&gt;Most globally remote companies that hire regardless of location solve this issue by legally treating everyone as a contractor. The responsibility then falls on the engineer who needs to handle taxes and the administration work by themselves in the country they reside in.&lt;/p&gt;

&lt;p&gt;We are making a focused post on this topic alone soon, but in short, this also means that if a software engineer is not prepared for this they might lose out on an opportunity because they do not understand the legal foundation on which they operate. Candidates must also understand that as contractors the contract to the hiring company is just that, a contract. Subsequently, that also means less employment security compared to if you were employed locally since contracts are often renewed on a fixed time basis and the terms might be unfavorable. &lt;/p&gt;

&lt;p&gt;We can make the assumption that companies who only hire in their own legal region, want to operate their business more predictably, and they also want to provide the same standard to all their employees. For example, health insurance, pension, vacation days, sick leave, and so forth works differently in almost all countries. Further, equity schemes which are a great way for companies to invest in their employees most likely do not work over international borders easily. &lt;/p&gt;

&lt;h3&gt;
  
  
  Tax Implications
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4vlbmrxo5jxk0yy6dwe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4vlbmrxo5jxk0yy6dwe.gif" alt="dog doing taxes" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the company has the intention of hiring a real employee, taxation is a critical concern for them when hiring internationally. Employing someone in a different country can introduce tax obligations not only for the employee but also for the employer in the employee's country of residence. This can include corporate taxes, payroll taxes, and other contributions that vary widely across jurisdictions. For companies, managing this tax landscape is challenging and often leads them to restrict job postings to regions where they are fully equipped to handle these obligations.&lt;/p&gt;

&lt;p&gt;Practically if the candidate is in a different country and they are &lt;strong&gt;not&lt;/strong&gt; going to be treated as a contractor, the company will need to register their company in that jurisdiction, officially employ them, set up bank accounts, and submit tax reports to that government regularly. This is not likely something a small to medium company has the capacity to do. &lt;/p&gt;

&lt;h3&gt;
  
  
  Offering Equitable Benefits
&lt;/h3&gt;

&lt;p&gt;Beyond legal and tax issues, there's the challenge of providing fair employee benefits. Health insurance, retirement savings plans, and other benefits are deeply tied to local laws and market standards. &lt;/p&gt;

&lt;p&gt;A benefits package that's competitive in one country might be lacking in another due to different expectations or requirements. Companies strive to offer fair and attractive benefits to all employees, but the variance in what that means across different countries can lead to geographic restrictions on job postings. &lt;/p&gt;

&lt;p&gt;Some companies offer services in this capacity helping hiring companies to bridge the gap but that comes at the cost of having another entity to deal with and obviously, they are not doing it for free.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collaboration and Time Zones
&lt;/h3&gt;

&lt;p&gt;Software engineering is a collaborative field. While asynchronous work is possible, real-time communication is sometimes crucial for team cohesion, brainstorming, and problem-solving. &lt;/p&gt;

&lt;p&gt;Time zone differences can make these interactions difficult, if not almost impossible, to coordinate when team members are spread too thinly across the globe. By restricting jobs to certain areas, companies aim to cluster their workforce within time zones that allow for efficient collaboration. &lt;/p&gt;

&lt;p&gt;There can be benefits of having the workforce spread over the world, for instance when it comes to server monitoring. The on-call schedule will be natural as people go on and off work as the world rotates. That is most a benefit for a larger company but most likely impossible for a smaller one.&lt;/p&gt;

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

&lt;p&gt;For software engineers looking for remote work, these restrictions might initially seem like unnecessary. However, they are rooted in legitimate challenges related to legal compliance, taxation, and the practicalities of managing a distributed team. If you understand these reasons it can help you navigate the remote job market more effectively. &lt;/p&gt;

&lt;p&gt;If asked during interviews it also shows that you have a fundamental grasp of what it means to work remotely. Not only in a worker capacity but also what responsibility you have towards the company. If you cannot handle your own taxes as a small business you will struggle in your role.&lt;/p&gt;

&lt;p&gt;As the remote work landscape continues to evolve, we might see more companies developing strategies to overcome these barriers, expanding the opportunities for software engineers to be "employed" across borders. But until then, if you are looking at global job postings, you will need to be prepared to also handle the extra administration that comes with that, together with the understanding that a substantial part of the money coming in will go to taxes and social fees. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4t6y1q80m0hzcldnzz9l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4t6y1q80m0hzcldnzz9l.gif" alt="stay cute gif" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  P.S.
&lt;/h3&gt;

&lt;p&gt;If you like this sort of content from engineers who have been working remotely for close to a decade consider creating an account at &lt;a href="https://remoet.dev"&gt;https://remoet.dev&lt;/a&gt; where we send and collect related information. Remote working is the future, and we need to be as informed as we can be. &lt;/p&gt;

&lt;p&gt;This post was created for &lt;a href="https://blog.remoet.dev"&gt;https://blog.remoet.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Making GraphQL Codegen Work For You: GraphQL Integration with React and TypeScript</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Wed, 01 Mar 2023 11:09:45 +0000</pubDate>
      <link>https://dev.to/novu/making-graphql-codegen-work-for-you-graphql-integration-with-react-and-typescript-3bbm</link>
      <guid>https://dev.to/novu/making-graphql-codegen-work-for-you-graphql-integration-with-react-and-typescript-3bbm</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;In this guide, we’ll be showing you how to use GraphQL alongside React and GraphQL Codegen to create a simple page that can pull data from an API and send emails. We’ll be using &lt;a href="https://novu.co/" rel="noopener noreferrer"&gt;Novu as an open source notification system&lt;/a&gt; for developers that can send our emails after being passed through a form created within React. &lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;We’ve all been there: you’ve been coding away in React with Typescript enjoying type-checking until it’s time to time to integrate your application with an API. And then, all of your data types are wrong, ending up with a ton of errors, or just not working at all. Thankfully, integrating APIs doesn’t need to be complicated with GraphQL. It enables you to quickly get an API integrated without the hassle of a standard REST API, thanks to tools like Codegen.&lt;/p&gt;

&lt;p&gt;In this article, I will demonstrate the problem that many developers face and how to improve the workflow when integrating your react app with a GraphQL API. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;This tutorial assumes that you have been working with React before and want to improve, so you already have your workstation set up.&lt;/em&gt;&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%2Fuploads%2Farticles%2Fcoswyh37xvdaji4yv0ez.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%2Fuploads%2Farticles%2Fcoswyh37xvdaji4yv0ez.png" alt="GraphQL Meme" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What We Will Do:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap&lt;/strong&gt; a new Next.js TypeScript project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt; Apollo GraphQL and fetch data from a public API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Showcase&lt;/strong&gt; why using GraphQL Codegen is a good idea&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create&lt;/strong&gt; a Next.js API endpoint for sending emails with data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the &lt;a href="http://Novu.co" rel="noopener noreferrer"&gt;Novu.co&lt;/a&gt; platform&lt;/strong&gt; for setting up and sending emails to a given email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;If you want to skip the writeup, you can go to GitHub directly and look at the code: &lt;a href="https://github.com/ugglr/next-typescript-graphql-integration" rel="noopener noreferrer"&gt;https://github.com/ugglr/next-typescript-graphql-integration&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Example Project with React and Next.js
&lt;/h2&gt;

&lt;p&gt;Learning is faster when you get your hands dirty, so let’s jump straight in. We’ll bootstrap a new React project using Next.js with Typescript. Next.js is a full-stack framework for React that allows us to quickly start up a web app.  &lt;/p&gt;

&lt;p&gt;Run the following command in your terminal to scaffold a new Next.js project with Typescript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create next-app &lt;span class="nt"&gt;--typescript&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will then prompt you for the name of the project. Let’s name it &lt;code&gt;next-typescript-graphql-integration&lt;/code&gt; so we know what we’re working with, and we’ll leave anything else to default values. &lt;/p&gt;

&lt;p&gt;While we’re still in the terminal, navigate to our newly created project and run it to make sure that the installation was successful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;next-typescript-graphql-integration

yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn dev
yarn run v1.22.15
&lt;span class="nv"&gt;$ &lt;/span&gt;next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully &lt;span class="k"&gt;in &lt;/span&gt;1457 ms &lt;span class="o"&gt;(&lt;/span&gt;165 modules&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this, we can determine that the page is available at &lt;strong&gt;localhost:3000&lt;/strong&gt;. Opening the browser and checking the page will show the default Next.js screen.&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%2Fuploads%2Farticles%2Fu4wp2jyxm6g732mq2d93.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%2Fuploads%2Farticles%2Fu4wp2jyxm6g732mq2d93.png" alt="Screenshot of Next.JS Default Page" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dependencies &amp;amp; Initialize Apollo Client
&lt;/h2&gt;

&lt;p&gt;We are now ready to install some packages. We start by installing one of the most popular GraphQL clients, &lt;a href="https://www.apollographql.com/apollo-client" rel="noopener noreferrer"&gt;Apollo Client&lt;/a&gt;. Apollo is a tool that enables devs to utilize GraphQL APIs within almost any tech stack and integrates it within your UI. Then, we’ll start doing some fetching from &lt;a href="https://studio.apollographql.com/public/rick-and-morty-a3b90u/home?variant=current" rel="noopener noreferrer"&gt;this public Rick &amp;amp; Morty GraphQL API&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @apollo/client graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When that’s done, let’s open up our code editor and initialize the Apollo Client. When inspecting the folder you can see that it’s a standard bare-bones Next project with the following folder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root
&lt;span class="nt"&gt;---&lt;/span&gt; .next
&lt;span class="nt"&gt;---&lt;/span&gt; pages
&lt;span class="nt"&gt;---&lt;/span&gt; public
&lt;span class="nt"&gt;---&lt;/span&gt; styles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside of &lt;code&gt;_app.tsc&lt;/code&gt; we can start initializing our client by following the steps described by the official &lt;a href="https://www.apollographql.com/docs/react/get-started/" rel="noopener noreferrer"&gt;Apollo Client React docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We include the necessary imports and create the client, then include it in our React app via &lt;code&gt;ApolloProvider&lt;/code&gt;. In the end, the file should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/styles/globals.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InMemoryCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://rickandmortyapi.com/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryCache&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ApolloProvider&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...{&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ApolloProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is everything we need to initialize our brand new GraphQL client on the client side. 🚀 Let’s continue with fetching some data &lt;strong&gt;the un-safe way&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching Data without Type Checking
&lt;/h2&gt;

&lt;p&gt;Now that we have our project up and running, it’s time to add some data from our API. If we want to get a list of characters from the API we need to run a query like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;
            &lt;span class="nx"&gt;species&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Apollo documentation will tell us to create the query document and then use it together with the &lt;code&gt;useQuery&lt;/code&gt; hook provided by Apollo. I’ve deleted everything in &lt;code&gt;index.tsx&lt;/code&gt; and replaced it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET_CHARACTERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  query {
    characters {
      results {
        id
        name
                species
      }
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GET_CHARACTERS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what it will look like, so let’s check back to our application:&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%2Fuploads%2Farticles%2Faiayfvm8nxv4jdfq6u3y.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%2Fuploads%2Farticles%2Faiayfvm8nxv4jdfq6u3y.png" alt=" " width="444" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything seems like it’s good, right? &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%2Fuploads%2Farticles%2F9ow8f335zezv9e1uml5m.jpg" 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%2Fuploads%2Farticles%2F9ow8f335zezv9e1uml5m.jpg" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Went Wrong with GraphQL?
&lt;/h2&gt;

&lt;p&gt;While our code may work as intended, it’s not exactly reliable. There are two common errors we made here that we need to look at:&lt;/p&gt;

&lt;h3&gt;
  
  
  No GraphQL Type Validation
&lt;/h3&gt;

&lt;p&gt;We didn’t add any type validation to our GraphQL calls. This means if you request a field that doesn’t exist in the schema, you will get weird and hard-to-understand error messages. Let’s see what can happen if we change our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET_CHARACTERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  query {
    characters {
      results {
        id
        name
        species
                notInSchema // 👈 this will result in error
      }
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this will give us an “Error! Response not successful: Received status code 400”, which doesn’t tell you what went wrong at all, becoming a huge time waster.&lt;/p&gt;

&lt;p&gt;Considering that some queries and mutations might have a variety of variables, fields, and subfields this gets complex &lt;strong&gt;fast&lt;/strong&gt; (believe me, I’ve done this to my breaking point before!). So you should be ensuring that your GraphQL queries don’t call for items not in the schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Types In The Response
&lt;/h3&gt;

&lt;p&gt;We also didn’t include any form of autocomplete in our response, so our code doesn’t know what is supposed to be returned from our API. We need to ensure that we validate the data we receive from our API to ensure our data is correct. If we don’t, this can become a nightmare in the future.&lt;/p&gt;

&lt;p&gt;Let’s take a look at our code editor. You should see a red line under the &lt;code&gt;character&lt;/code&gt; variable with the following Typescript validation error:&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%2Fuploads%2Farticles%2Fd3xti92ccmh0jw3pm65o.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%2Fuploads%2Farticles%2Fd3xti92ccmh0jw3pm65o.png" alt=" " width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how do we fix this issue?&lt;/p&gt;

&lt;p&gt;If we’re just building something small, we can create our own type like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetCharactersQueryResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nl"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then passing it into our query hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GetCharactersQueryResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GET_CHARACTERS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us type-checking from Typescript and work just fine. &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%2Fuploads%2Farticles%2Fp9ix9r7c5xjgslhrebg1.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%2Fuploads%2Farticles%2Fp9ix9r7c5xjgslhrebg1.png" alt=" " width="780" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this solution becomes a nightmare when return types become large or if you need to pass variables. All of those are checked in the GraphQL API and will send you confusing errors that are hard to debug. &lt;/p&gt;

&lt;p&gt;Fortunately, there are some smart people who realized that all this information is already available inside GraphQL schemas &amp;amp; can be used to generate this information for us.  &lt;/p&gt;

&lt;p&gt;Enter: GraphQL Codegen 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Graphql Codegen?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dotansimha/graphql-code-generator" rel="noopener noreferrer"&gt;Graphql Codegen&lt;/a&gt; is a code generation library for GraphQL that enables developers to generate custom code. It provides us developers with the ability to generate type definitions, query builders, documentation, and more by analyzing our GraphQL schemas. This makes it easier and faster to build GraphQL applications and reduces the time spent coding.&lt;/p&gt;

&lt;p&gt;Additionally, Graphql Codegen is also a type-safe code generator. This means that the generated code is checked for errors by the Graphql Codegen compiler &lt;strong&gt;before&lt;/strong&gt; it is used in an application. This ensures that any errors in the code are caught before they cause problems in production.&lt;/p&gt;

&lt;p&gt;Plus, it also provides developers with an easy way to manage GraphQL schemas. It allows devs to easily add, remove, and update their schemas without any hassle. This makes it much easier to keep your schemas up-to-date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and Configuring GraphQL Codegen
&lt;/h2&gt;

&lt;p&gt;Before we can start using Graphql Codegen, we’ll need to configure it. This process is relatively simple and can be done in a few steps:&lt;/p&gt;

&lt;p&gt;The first step is installing GraphQL Codegen by running this command 👨‍💻&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-graphql-request @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This will install the following packages as &lt;code&gt;devDepencencies&lt;/code&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@graphql-codegen/cli&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@graphql-codegen/typescript&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@graphql-codegen/typescript-graphql-request&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@graphql-codegen/typescript-operations&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@graphql-codegen/typescript-react-apollo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After installing, we need to configure GraphQL Codegen. I prefer to do this by adding a &lt;code&gt;.yml&lt;/code&gt; file to the root of our directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;graphql.config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up the file and let’s add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;schema:
  - &lt;span class="s2"&gt;"https://rickandmortyapi.com/graphql"&lt;/span&gt; 
documents:
  - &lt;span class="s2"&gt;"./graphql/**/*.graphql"&lt;/span&gt;
generates:
  ./generated/graphql.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-react-apollo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The configuration file does the following:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;schema&lt;/code&gt; This points to our GraphQL endpoint for fetching the API schema map.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;documents&lt;/code&gt; This tells GraphQL Codegen where to look for our schema files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;generates&lt;/code&gt; This tells GraphQL Codegen where to create and store generated code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;plugins&lt;/code&gt; Specifies what GraphQL Codegen plugins to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To finalize the setup we also need to add the generation 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 json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next-typescript-graphql-integration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next lint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"generate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"graphql-codegen --config graphql.config.yml"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;👈&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@apollo/client"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.7.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@next/font"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"13.1.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18.11.18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18.0.27"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18.0.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eslint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8.33.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eslint-config-next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"13.1.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"graphql"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.6.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"13.1.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.9.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@graphql-codegen/cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@graphql-codegen/typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@graphql-codegen/typescript-graphql-request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.5.8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@graphql-codegen/typescript-operations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@graphql-codegen/typescript-react-apollo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.3.7"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;If you run &lt;code&gt;yarn generate&lt;/code&gt; now you will see an error output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn generate
yarn run v1.22.15
&lt;span class="nv"&gt;$ &lt;/span&gt;graphql-codegen &lt;span class="nt"&gt;--config&lt;/span&gt; ./graphql.config.yml
&lt;span class="o"&gt;(&lt;/span&gt;node:15632&lt;span class="o"&gt;)&lt;/span&gt; ExperimentalWarning: stream/web is an experimental feature. This feature could change at any &lt;span class="nb"&gt;time&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;Use &lt;span class="sb"&gt;`&lt;/span&gt;node &lt;span class="nt"&gt;--trace-warnings&lt;/span&gt; ...&lt;span class="sb"&gt;`&lt;/span&gt; to show where the warning was created&lt;span class="o"&gt;)&lt;/span&gt;
✔ Parse Configuration
❯ Generate outputs
✔ Parse Configuration
⚠ Generate outputs
  ❯ Generate to ./generated/graphql.ts
    ✔ Load GraphQL schemas
    ✖
      Unable to find any GraphQL &lt;span class="nb"&gt;type &lt;/span&gt;definitions &lt;span class="k"&gt;for &lt;/span&gt;the f…
      - ./graphql/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.graphql
    ◼ Generate
error Command failed with &lt;span class="nb"&gt;exit &lt;/span&gt;code 1.
info Visit https://yarnpkg.com/en/docs/cli/run &lt;span class="k"&gt;for &lt;/span&gt;documentation about this command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the setup is complete and we are ready to add some schema files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Our Schema File
&lt;/h2&gt;

&lt;p&gt;Starting off, create a folder in the root of the directory called &lt;code&gt;graphql&lt;/code&gt;, and inside create a file called &lt;code&gt;get-characters.query.graphql&lt;/code&gt;. We already told Codegen where to look for our schemas, but the second filename is up to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The folder structure now looks like this 👇&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root
&lt;span class="nt"&gt;---&lt;/span&gt; .next
&lt;span class="nt"&gt;---&lt;/span&gt; pages
&lt;span class="nt"&gt;---&lt;/span&gt; public
&lt;span class="nt"&gt;---&lt;/span&gt; styles
&lt;span class="nt"&gt;---&lt;/span&gt; graphql 👈 here 🤩
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inside of the file &lt;code&gt;get-characters.query.graphql&lt;/code&gt;, add the query that we previously used, but without wrapping it in a &lt;code&gt;gql&lt;/code&gt; template string, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="nx"&gt;GetCharacters&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="nx"&gt;species&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then re-run the &lt;code&gt;generate&lt;/code&gt; script, and you will see the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn generate
yarn run v1.22.15
&lt;span class="nv"&gt;$ &lt;/span&gt;graphql-codegen &lt;span class="nt"&gt;--config&lt;/span&gt; ./graphql.config.yml
&lt;span class="o"&gt;(&lt;/span&gt;node:16009&lt;span class="o"&gt;)&lt;/span&gt; ExperimentalWarning: stream/web is an experimental feature. This feature could change at any &lt;span class="nb"&gt;time&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;Use &lt;span class="sb"&gt;`&lt;/span&gt;node &lt;span class="nt"&gt;--trace-warnings&lt;/span&gt; ...&lt;span class="sb"&gt;`&lt;/span&gt; to show where the warning was created&lt;span class="o"&gt;)&lt;/span&gt;
✔ Parse Configuration
❯ Generate outputs
✔ Parse Configuration
✔ Generate outputs
✨  Done &lt;span class="k"&gt;in &lt;/span&gt;7.43s.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! We are almost done. Now, check &lt;code&gt;root&lt;/code&gt; and you will notice that the script has created a new folder called &lt;code&gt;generated&lt;/code&gt; with a file called &lt;code&gt;graphql.ts&lt;/code&gt;. This is as we configured in the &lt;code&gt;graphql.config.file&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root
&lt;span class="nt"&gt;---&lt;/span&gt; .next
&lt;span class="nt"&gt;---&lt;/span&gt; pages
&lt;span class="nt"&gt;---&lt;/span&gt; public
&lt;span class="nt"&gt;---&lt;/span&gt; styles
&lt;span class="nt"&gt;---&lt;/span&gt; graphql 
&lt;span class="nt"&gt;---&lt;/span&gt; generated 👈 here 👀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you inspect that file you can see that we have generated a bunch of types pulled from the API and generated custom React hooks for the query that we authored in &lt;code&gt;get-characters.query.graphql&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  GraphQL Codegen in Action
&lt;/h2&gt;

&lt;p&gt;Now that you have Graphql Codegen set up and configured, you can start using it in your React application. Let’s modify &lt;code&gt;index.tsx&lt;/code&gt;to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;GetCharactersDocument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;GetCharactersQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;GetCharactersQueryVariables&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/generated/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@apollo/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nx"&gt;GetCharactersQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;GetCharactersQueryVariables&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GetCharactersDocument&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No name: something is wrong&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, our data is type-safe and validated. If there was something wrong within the query that didn’t match the API, it would have thrown an error during generation. Now, inside our component, we now have fully typed data, which can be demonstrated by hovering over &lt;code&gt;character&lt;/code&gt;.&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%2Fuploads%2Farticles%2Fftmp7xkh92d4nxf62np0.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%2Fuploads%2Farticles%2Fftmp7xkh92d4nxf62np0.png" alt=" " width="780" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But where are the custom hooks?&lt;/p&gt;

&lt;p&gt;Let’s take it one step further and use the &lt;code&gt;typescript-react-apollo&lt;/code&gt; plugin we told GraphQL Codegen to use. This will make our code &lt;em&gt;super&lt;/em&gt; clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Generated End-To-End Type-Safe Apollo Hooks
&lt;/h2&gt;

&lt;p&gt;Let’s clean up our code a little bit to something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetCharactersQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/generated/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// This hook is validated towards the API &amp;amp; will infer &lt;/span&gt;
  &lt;span class="c1"&gt;// types and throw you type errors if you have not&lt;/span&gt;
  &lt;span class="c1"&gt;// provided the right variables.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGetCharactersQuery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          &lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No name: something is wrong&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at how neat and clean that is! 🤩 And it’s still typed, too!&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%2Fuploads%2Farticles%2Fspp3o8zgm1iufya54tcv.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%2Fuploads%2Farticles%2Fspp3o8zgm1iufya54tcv.png" alt=" " width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this project to continue API integration, all developers need to do is add new files into the &lt;code&gt;graphql&lt;/code&gt; folder and run &lt;code&gt;yarn generate&lt;/code&gt; before restarting the dev server. Then, everything gets generated automatically.&lt;/p&gt;

&lt;p&gt;One more check to see if it works. &lt;strong&gt;Don’t forget to start your development server if you stopped it.&lt;/strong&gt;&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%2Fuploads%2Farticles%2Fz3asr2rsdr4vlmyr99gj.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%2Fuploads%2Farticles%2Fz3asr2rsdr4vlmyr99gj.png" alt=" " width="506" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously, this is a very small app so far. Even so, I think I have been able to demonstrate that even at this scale, GraphQL Codegen is a very valuable tool. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Best Practices for GraphQL Codegen&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There are some best practices that developers should follow when using GraphQL Codegen:&lt;/p&gt;

&lt;p&gt;First, it is important to keep your GraphQL Codegen configuration file up-to-date. This will ensure that the generated code is always accurate. It’s also important to make sure your configuration file is well-structured and easy to understand. This makes it easier for changes in the future.&lt;/p&gt;

&lt;p&gt;Second, for production projects, it is important to &lt;strong&gt;test your generated code&lt;/strong&gt;. This ensures the code is working as expected and any errors are caught before they cause problems in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding In New Functionality With Novu
&lt;/h2&gt;

&lt;p&gt;Showing data is pretty neat, but what if we could aggregate that data and send it to our users?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For this, we can use Novu!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Novu is an &lt;a href="https://novu.co/" rel="noopener noreferrer"&gt;open-source notification infrastructure&lt;/a&gt; for developers. They make it possible to send notifications though a unified API. With their platform, it’s possible to bundle notification sending into “triggers”. &lt;/p&gt;

&lt;p&gt;Managing all notification handlers normally becomes a big chore for us developers as our applications become more complex. Only handling code for email notifications might be doable in a small team, but adding in SMS and push notifications quickly becomes a time drain to get up and running. Which is exactly what Novu intends to help with.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Get Started with Novu&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The quickest way to get started with Novu is by &lt;a href="https://web.novu.co/auth/signup" rel="noopener noreferrer"&gt;signing up for their cloud platform&lt;/a&gt;. Its totally free, and with a generous free tier of 10k events per month, you’ll have plenty to work with. There is also the option to self-host the platform on your own servers but will require extra work. For this tutorial, we’ll be going with the simpler option through Novu’s cloud platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Sign Up
&lt;/h3&gt;

&lt;p&gt;After signing up they will ask for an organization name, and then you will be greeted with a welcome screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Connect the Novu Email Provider
&lt;/h3&gt;

&lt;p&gt;For most providers, Novu sits between them and your application. That means if you are sending an SMS to your user, Novu doesn’t send that, it’s done by your provider. &lt;/p&gt;

&lt;p&gt;However, to get started, I recommend using their built-in email provider. It lets you send up to 300 emails, which is plenty for small applications like ours. The emails will come from &lt;em&gt;&lt;a href="mailto:no-reply@novu.co"&gt;no-reply@novu.co&lt;/a&gt;,&lt;/em&gt; and the sending will be the organization name you picked earlier. &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%2Fuploads%2Farticles%2Fxtogepx1gsu4wyujb5mn.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%2Fuploads%2Farticles%2Fxtogepx1gsu4wyujb5mn.png" alt=" " width="800" height="521"&gt;&lt;/a&gt;&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%2Fuploads%2Farticles%2F6jp03prkvruim1svx2xt.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%2Fuploads%2Farticles%2F6jp03prkvruim1svx2xt.png" alt=" " width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create a New Notification Trigger
&lt;/h3&gt;

&lt;p&gt;We also need to define a trigger by going to &lt;strong&gt;Notifications&lt;/strong&gt; in the cloud panel.&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%2Fuploads%2Farticles%2F457059yasabje3wsm8tm.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%2Fuploads%2Farticles%2F457059yasabje3wsm8tm.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press &lt;strong&gt;New&lt;/strong&gt; and add our trigger.&lt;/p&gt;

&lt;p&gt;This is what our settings should look like, but feel free to switch it up if you want:&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%2Fuploads%2Farticles%2F0440u3l15lfxt8xpxbml.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%2Fuploads%2Farticles%2F0440u3l15lfxt8xpxbml.png" alt=" " width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then head into the &lt;strong&gt;Workflow Editor&lt;/strong&gt; and configure what happens when triggered.&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%2Fuploads%2Farticles%2Fi32m8g3ez437ns3cywtl.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%2Fuploads%2Farticles%2Fi32m8g3ez437ns3cywtl.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add an email field and then enter the email editor to edit the template or any other settings you’d like to add.&lt;/p&gt;

&lt;p&gt;Email templates often inject variables with &lt;code&gt;{{ VARIABLE }}&lt;/code&gt;. This is how we’ll inject the request payload into our email template. Apply variables in the editor, and you’ll see them show up in the variables box. In this case, &lt;code&gt;{{ name }}&lt;/code&gt; and &lt;code&gt;{{ species }}&lt;/code&gt; will need to be present in the payload we send to the API. This is what our template should look like:&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%2Fuploads%2Farticles%2Fxpn579phubkom76h3b7i.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%2Fuploads%2Farticles%2Fxpn579phubkom76h3b7i.png" alt=" " width="800" height="826"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press update and see that the payload variables show up in the variables box:&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%2Fuploads%2Farticles%2Fgn3i4d0nifcq52jk209r.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%2Fuploads%2Farticles%2Fgn3i4d0nifcq52jk209r.png" alt=" " width="676" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s all we need for now! Let’s continue with writing the components and wire everything together. 🪡&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create the React Form Component
&lt;/h3&gt;

&lt;p&gt;Let's jump back into the code and create a form to take our users’ email and store it locally.&lt;/p&gt;

&lt;p&gt;We will create a folder in &lt;code&gt;root&lt;/code&gt; called &lt;code&gt;components&lt;/code&gt;, with a file called &lt;code&gt;EmailForm.tsx&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EmailForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSuccess&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// send the email to user&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Send me random character 🚀&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Send!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;EmailForm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our form set up and ready to go, we can connect it to the Novu API!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Install Novu-client
&lt;/h3&gt;

&lt;p&gt;The easiest way to interact with the Novu API is to install their client package. We can install the &lt;code&gt;@novu/node&lt;/code&gt; package from npm by running &lt;code&gt;yarn add @novu/node&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After this, create a folder in &lt;code&gt;root&lt;/code&gt; called &lt;code&gt;lib&lt;/code&gt; which will hold the logic for interacting with the Novu API. We’ll call it &lt;code&gt;novu.ts&lt;/code&gt;, and it’s going to export an async function which we can then re-use.&lt;/p&gt;

&lt;p&gt;Then, we’ll head into the &lt;strong&gt;Novu Dashboard&lt;/strong&gt; and grab this Node.js code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Novu&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@novu/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;novu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Novu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;API_KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;novu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;randm-random-email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;subscriberId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;REPLACE_WITH_DATA&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;REPLACE_WITH_DATA&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;REPLACE_WITH_DATA&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;REPLACE_WITH_DATA&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty neat! They’ve done most of the work for us ☕️. Novu adds the payload variables and everything, saving us time from going to the docs.&lt;/p&gt;

&lt;p&gt;Now back to the editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/novu.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Novu&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@novu/node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;novu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Novu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;API_KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;novu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;REPLACE_WITH_TRIGGER_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;subscriberId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how the payload should look in the new &lt;code&gt;Payload&lt;/code&gt; type, which will be sent to Novu and injected into our email template. Replace &lt;code&gt;API_KEY&lt;/code&gt; and &lt;code&gt;TRIGGER_ID&lt;/code&gt; with our variables, and we should be good to go!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Before pushing this to git, please make sure you’re using environmental variables, not what’s shown in this tutorial.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Create a Next.js API Endpoint
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; is a full-stack framework for React, and they make it easy for us to create full-stack apps. One of the most notable features is that we can create API endpoints on our server. These are then hidden from the client browser for extra security.&lt;/p&gt;

&lt;p&gt;The way these works is by adding a new file to our &lt;code&gt;pages&lt;/code&gt; folder and using the folder structure to define our endpoints. The below structure will create an endpoint at &lt;code&gt;/send-email&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;root&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt;
        &lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;
                &lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
                &lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; 
&lt;span class="o"&gt;---&lt;/span&gt; &lt;span class="nx"&gt;generated&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And here’s the code for the handler, where we get our parameters from the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sendEmail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/novu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// we are only handling post requests.&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;species&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// return bad request status.&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;species&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Just response internal server error;&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This handler will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look at any incoming &lt;code&gt;POST&lt;/code&gt; requests to the endpoint &lt;/li&gt;
&lt;li&gt;Check if the body of the request has the necessary params &lt;/li&gt;
&lt;li&gt;Send the email if everything is correct, or return an error if something is wrong&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s all we need for our backend! So let’s add in the client-side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Add Our Email Functionality
&lt;/h3&gt;

&lt;p&gt;Now that we’re back at the client-side, let’s add in the rest of the functionality. We’ll start at the top of the tree in &lt;code&gt;index.tsx&lt;/code&gt; and import our &lt;code&gt;EmailForm.tsx&lt;/code&gt; component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetCharactersQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/generated/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;EmailForm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/EmailForm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGetCharactersQuery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EmailForm&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...{&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No name: something is wrong&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was simple! Let’s finish the implementation in &lt;code&gt;EmailForm.tsx&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Character&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/generated/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Character&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EmailForm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Get random character from the array.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;random&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;randomCharacter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="c1"&gt;// Make send email request to /api/send-email&lt;/span&gt;
      &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/api/send-email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;randomCharacter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;randomCharacter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Send me random character 🚀&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Send!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;EmailForm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This form component will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render a text input for email, and store the data in local storage&lt;/li&gt;
&lt;li&gt;Submit the data when the button has been pressed&lt;/li&gt;
&lt;li&gt;Makes a request to our API which sends a request to &lt;a href="http://Novu.co" rel="noopener noreferrer"&gt;Novu.co&lt;/a&gt;, which in turn will send en email to the given email address&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s it! Now we need to test it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Send Emails!
&lt;/h3&gt;

&lt;p&gt;If we take a look in the browser at this point, it 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%2Fuploads%2Farticles%2F7nyfcgs4vm0jwr4x7mrg.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%2Fuploads%2Farticles%2F7nyfcgs4vm0jwr4x7mrg.png" alt=" " width="454" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s not pretty, but it’s functional!&lt;/p&gt;

&lt;p&gt;Enter your email and see if it shows up in your inbox!&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%2Fuploads%2Farticles%2Fazxoqgrg0p3sgmys6bm6.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%2Fuploads%2Farticles%2Fazxoqgrg0p3sgmys6bm6.png" alt=" " width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping It Up
&lt;/h2&gt;

&lt;p&gt;Integrating APIs into a project can be difficult, but it doesn’t have to be. And with GraphQL, it’s easier than ever before! It allows you to set up API integrations with ease and can pair with tools like GraphQL Codegen to automate some of the hassles. &lt;/p&gt;

&lt;p&gt;Paired with a powerful notification platform like Novu, you can easily get a project up and running in no time, with notifications and communication options at your disposal. &lt;/p&gt;

&lt;p&gt;And the best part? You can do it all for free! No buy-in required. I know I’ll be using Novu in my future, what about you?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full source code can be found here &lt;a href="https://github.com/ugglr/next-typescript-graphql-integration" rel="noopener noreferrer"&gt;https://github.com/ugglr/next-typescript-graphql-integration&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>blockchain</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Helping developers find remote jobs since 2019</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Sun, 08 Jan 2023 06:30:01 +0000</pubDate>
      <link>https://dev.to/ugglr/helping-developers-find-remote-jobs-since-2019-d16</link>
      <guid>https://dev.to/ugglr/helping-developers-find-remote-jobs-since-2019-d16</guid>
      <description>&lt;h1&gt;
  
  
  TLDR
&lt;/h1&gt;

&lt;p&gt;I just launched a website where I have collected resources for developers to look for remote jobs. There are over 200 companies that work remotely and hire engineers, and then there are some other resources like job boards and online communities. &lt;/p&gt;

&lt;p&gt;If this sounds interesting to you do check it out, it's all free, and I'm adding companies and features as time permits.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://remoet.dev"&gt;https://remoet.dev&lt;/a&gt; 👈&lt;/p&gt;

&lt;p&gt;I also submitted it to ProductHunt if you like the project do consider checking it out there and support it so more people can get access.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.producthunt.com/posts/remoet-dev"&gt;https://www.producthunt.com/posts/remoet-dev&lt;/a&gt; 👈&lt;/p&gt;

&lt;p&gt;If you want to know a little bit of the back story and overall reasoning do continue with this post. 👇&lt;/p&gt;

&lt;h1&gt;
  
  
  How it started
&lt;/h1&gt;

&lt;p&gt;Back in 2019, I was making the infamous switch to Software Engineering and for location reasons, I had to go remote. &lt;/p&gt;

&lt;p&gt;It was a lot of hard work, late nights, tutorials, and janky projects. It almost broke me, and I almost gave up on the idea. Because I was alone, I had no contacts, and being seen on the internet is not easy.&lt;/p&gt;

&lt;p&gt;This was pre-pandemic and my perception was that very few companies were adopting the remote model. But I was wrong, and it gave me the confidence to continue grinding. &lt;/p&gt;

&lt;p&gt;I wrote my story down here if you are interested: &lt;a href="https://dev.to/ugglr/junior-developers-checklist-for-landing-a-remote-job-2ldb"&gt;https://dev.to/ugglr/junior-developers-checklist-for-landing-a-remote-job-2ldb&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Being in good company
&lt;/h1&gt;

&lt;p&gt;During my job search, I collected all the resources I could find into a Github repo: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ugglr/Remote-Developer-jobs-directory"&gt;https://github.com/ugglr/Remote-Developer-jobs-directory&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and the sheer amount of companies who work remotely just blew my mind 🤯 Further this motivated me to keep going 💪 Because every day I could find a new awesome company to apply to or I could circle back to other companies in the list and see if they have any new job postings out.&lt;/p&gt;

&lt;p&gt;This proved to be a much more solid strategy than applying through job postings on job boards. Because when you apply directly to a company you interact with them, and not through a middleman. &lt;/p&gt;

&lt;h1&gt;
  
  
  Job boards are a lottery
&lt;/h1&gt;

&lt;p&gt;I must have applied to thousands of jobs through different job boards and I most often never heard anything back. This is not surprising because there is no friction in applying for a job on those sites. Many times it's a one-click deal and that means each post will be flooded with an ocean of applicants. &lt;/p&gt;

&lt;p&gt;This is a problem for both serious applicants but also for employers, because how to shift through that amount of people in a reasonable amount of time?&lt;/p&gt;

&lt;p&gt;In my opinion, it's a lottery, and not a valid strategy anymore. The chances of actually getting to interact with the company are close to zero.&lt;/p&gt;

&lt;h1&gt;
  
  
  What I would do if I was looking for a new remote job?
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Do your research. Find companies that resonate with you and fit your general situation. Many companies, even though they are remote, have location restrictions. So pay attention. &lt;a href="https://remoet.dev"&gt;https://remoet.dev&lt;/a&gt; is a good place to start but there are other ways to find remote companies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check their careers page directly, look for jobs that apply to you, and organize a strategy for applying to them. Every company's application process will be slightly different.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try to network with people who work inside the companies. Twitter is a great place to start building connections and is one of the most important tools for developers to create a virtual network. Comment on posts, be helpful, and hopefully, you can ask for a referral when an opening comes around.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create content about your journey, it might include learnings in form of blog posts, or it might be vlogs uploaded on youtube or even just Twitter. It will make you stand out, but remember the point is to make an honest representation of who you are. I don't recommend adopting an over-the-top persona that is not genuine. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build projects with a wide variety within your code niche. If you managed to gather attention, you also need to show that you got the skills, because, by the end of the day, that's what matters. Your job is to create value and solve problems with code. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's all I have to say for now. &lt;/p&gt;

&lt;h1&gt;
  
  
  Support the project
&lt;/h1&gt;

&lt;p&gt;Check out the site &lt;a href="https://remoet.dev"&gt;https://remoet.dev&lt;/a&gt; and if you think it might be helpful for others consider sharing it within your network. The more people use it the more I'm motivated to create new helpful features. &lt;/p&gt;

&lt;p&gt;Support us on Producthunt &lt;a href="https://www.producthunt.com/posts/remoet-dev"&gt;https://www.producthunt.com/posts/remoet-dev&lt;/a&gt; Check us out and maybe even share it with your friends. &lt;/p&gt;

&lt;p&gt;The original repo is still up: &lt;a href="https://github.com/ugglr/Remote-Developer-jobs-directory"&gt;https://github.com/ugglr/Remote-Developer-jobs-directory&lt;/a&gt; If you are more inclined to stay on Github that's a good resource as well (although some things might be outdated by now).&lt;/p&gt;

&lt;h1&gt;
  
  
  Thanks for reading 🤓 Happy job hunting.
&lt;/h1&gt;

</description>
      <category>career</category>
      <category>programming</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Events driven analytics service powered by Mongo Atlas</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Sun, 09 Jan 2022 09:24:41 +0000</pubDate>
      <link>https://dev.to/ugglr/events-driven-analytics-service-powered-by-mongo-atlas-5ck4</link>
      <guid>https://dev.to/ugglr/events-driven-analytics-service-powered-by-mongo-atlas-5ck4</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zm9sj3y26giapwm3y2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zm9sj3y26giapwm3y2t.png" alt="mongo image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;When utilising MongoDB Atlas charting tools one can with little code create an events driven analytics service. It's a magical feature where we can get charts with data straight from the DB.  &lt;/p&gt;

&lt;p&gt;By creating your own service we can keep as much or as little of our users data as we want in-house without worrying about sharing sensitive information with third party products or services. It is also possible to extend the service endlessly to fit all types of applications, or with further request relay mechanisms. For instance relaying events to Facebook conversion API.&lt;/p&gt;

&lt;p&gt;And since we are just making post requests over http our clients can be very thing, without pulling in any external SDKs or big npm packages.&lt;/p&gt;

&lt;p&gt;There are two parts to my submission:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The backend - which collects all the events and stores them into mongodb atlas&lt;/li&gt;
&lt;li&gt;The example app - The app mimics a regular landing page with a couple of CTA buttons and navigation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Backend
&lt;/h3&gt;

&lt;p&gt;The backend consists of a Nest.js server running graphql where the events get's stored into mongodb. It's nothing fancy it's just a create function for the events. &lt;/p&gt;

&lt;p&gt;One thing of note is that there is no resolver / query where one can get the events out from the server. So it's completely blocked from the outside world. Events goes in but events cannot be queried. &lt;/p&gt;

&lt;p&gt;Except in mongodb charts where we grant a service account read rights to make the charts. So there's no need to do any data aggregation on the server, mongodb atlas handles that for you, and with a little bit of getting used to even non-coding people in the organisation can make charts at their will. &lt;/p&gt;

&lt;h3&gt;
  
  
  The example app
&lt;/h3&gt;

&lt;p&gt;This part of the submission is just a simple landing website with two pages written in react. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jicbkz59ehsgja83xd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jicbkz59ehsgja83xd7.png" alt="example app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the first page&lt;/strong&gt; (home), there are a few elements which are common to all websites where the user takes some type of action and where we want to track the analytics. &lt;/p&gt;

&lt;p&gt;I've added sending tracking events on the CTA buttons, and the navigation. &lt;/p&gt;

&lt;p&gt;And the events are called:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CTA1 clicked!&lt;/li&gt;
&lt;li&gt;CTA2 clicked!&lt;/li&gt;
&lt;li&gt;CTA3 clicked!&lt;/li&gt;
&lt;li&gt;Navigation: home&lt;/li&gt;
&lt;li&gt;Navigation: analytics&lt;/li&gt;
&lt;li&gt;Navigation: logo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the events that then makes up the charts on the analytics page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mobvdt1dj1003p5ym57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mobvdt1dj1003p5ym57.png" alt="analytics page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the second page&lt;/strong&gt; (analytics), there is an &lt;code&gt;Analytics&lt;/code&gt; page where I display the use of the events by using MongoDB Atlas charting functionality. The charts are created in the mongodb atlas cloud website and then embedded into the page using iframes provided by the charting tools.&lt;/p&gt;

&lt;p&gt;This is really cool because to make new charts does not require any coding, and can me made on the fly, or in personal dashboards, or as in this case embedded into any website. One can aggregate the data right on the dataset, while none of the events are query-able from the server.   &lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Own Adventure (I think 🤔)&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ugglr" rel="noopener noreferrer"&gt;
        ugglr
      &lt;/a&gt; / &lt;a href="https://github.com/ugglr/dev-mongodb-hackathon" rel="noopener noreferrer"&gt;
        dev-mongodb-hackathon
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Events driven analytics service created with MongoDB, TS, Nest.js and caffeine
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;dev.to MongoDB Hackathon project&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;By using MongoDB charting tools it's easy to setup ones own events driven analytics server. It's flexibility is far superior than using a SAAS, all the while keeing your users data safe and secure and not sharing it to any third partys unknowningly.&lt;/p&gt;
&lt;p&gt;Demonstration Links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;backend: &lt;a href="https://devmongo.herokuapp.com/" rel="nofollow noopener noreferrer"&gt;https://devmongo.herokuapp.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;frontend: &lt;a href="https://goofy-galileo-d36254.netlify.app/" rel="nofollow noopener noreferrer"&gt;https://goofy-galileo-d36254.netlify.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Built with&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;nest.js&lt;/li&gt;
&lt;li&gt;mongodb&lt;/li&gt;
&lt;li&gt;mongoose&lt;/li&gt;
&lt;li&gt;graphql&lt;/li&gt;
&lt;li&gt;apollo server + client&lt;/li&gt;
&lt;li&gt;react&lt;/li&gt;
&lt;li&gt;typescript&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;a href="http://nestjs.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1e169f71fc9ed248abe0abaeebcd1524e058c5be3386a619569b9a4be2963288/68747470733a2f2f6e6573746a732e636f6d2f696d672f6c6f676f5f746578742e737667" width="320" alt="Nest Logo"&gt;&lt;/a&gt;
&lt;/p&gt;


&lt;p&gt;A progressive &lt;a href="http://nodejs.org" rel="nofollow noopener noreferrer"&gt;Node.js&lt;/a&gt; framework for building efficient and scalable server-side applications.&lt;/p&gt;
&lt;br&gt;
    &lt;p&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/~nestjscore" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/24dfd27aa1b2b7b9b523f5eaf2c6abf33084588f7f567553ad9e4b36113b5717/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f406e6573746a732f636f72652e737667" alt="NPM Version"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/~nestjscore" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b7c951e242d9686b460a9eab8b265d7240f84b29a79c299c648aa95d64bf8440/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f406e6573746a732f636f72652e737667" alt="Package License"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/~nestjscore" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7b83739222090e241d71c5fd4938703c7dedfafef0cde0d96022c3cf9b3a57ca/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f406e6573746a732f636f6d6d6f6e2e737667" alt="NPM Downloads"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://circleci.com/gh/nestjs/nest" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/90e78bdb27156e5275cdb3028402d4cc16b313c300b8dfdadd865455164d68ad/68747470733a2f2f696d672e736869656c64732e696f2f636972636c6563692f6275696c642f6769746875622f6e6573746a732f6e6573742f6d6173746572" alt="CircleCI"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://coveralls.io/github/nestjs/nest?branch=master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3c5d9fe3d2b47c6e02dd884319a0049859d22493dc47665d219edfaa4412632b/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6e6573746a732f6e6573742f62616467652e7376673f6272616e63683d6d61737465722339" alt="Coverage"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://discord.gg/G7Qnnhy" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/418492403803275197fbce1084b95b08d56ad9c7d2a0d6d3fa70dea12ff31284/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646973636f72642d6f6e6c696e652d627269676874677265656e2e737667" alt="Discord"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opencollective.com/nest#backer" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ebdc9e103775edc0db99103676102f341ba228170356d4e069dfef64ef635593/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6e6573742f6261636b6572732f62616467652e737667" alt="Backers on Open Collective"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opencollective.com/nest#sponsor" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e95a1e851cf02fe970fce3fd496498c907a566aef7b32edbe699fb701e1fdbc/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6e6573742f73706f6e736f72732f62616467652e737667" alt="Sponsors on Open Collective"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;a href="https://paypal.me/kamilmysliwiec" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4f9ed737abe81e3e0c3278f57f87fe09674513cb858c4a7dd0712c795e75c39b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f6e6174652d50617950616c2d6666336635392e737667"&gt;&lt;/a&gt;&lt;br&gt;
    &lt;a href="https://opencollective.com/nest#sponsor" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fab509818f8e438f1f2e4d7b42baf9d12b6bf45b2ad80fd338a764334867bf47/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f537570706f727425323075732d4f70656e253230436f6c6c6563746976652d3431423838332e737667" alt="Support us"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;a href="https://twitter.com/nestframework" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e984f5b62ec34062df9b35352b3c756486e5b83f9dc33d14116286cd40f5f071/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f6e6573746672616d65776f726b2e7376673f7374796c653d736f6369616c266c6162656c3d466f6c6c6f77"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/nestjs/nest" rel="noopener noreferrer"&gt;Nest&lt;/a&gt; framework TypeScript starter repository.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ npm install&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running the app&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; development&lt;/span&gt;
$ npm run start

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; watch mode&lt;/span&gt;
$ npm run start:dev

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; production mode&lt;/span&gt;
$ npm run start:prod&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Test&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; unit tests&lt;/span&gt;
$ npm run &lt;span class="pl-c1"&gt;test&lt;/span&gt;

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; e2e tests&lt;/span&gt;
$ npm run test:e2e

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; test coverage&lt;/span&gt;
$ npm run test:cov&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Support&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ugglr/dev-mongodb-hackathon" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;[Note:] # (Be sure to link to any open source projects that are using your workflow!)&lt;/p&gt;

&lt;p&gt;I wrote the service using Nest.js for the backend, and react for the frontend. &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nestjs" rel="noopener noreferrer"&gt;
        nestjs
      &lt;/a&gt; / &lt;a href="https://github.com/nestjs/nest" rel="noopener noreferrer"&gt;
        nest
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a href="https://nestjs.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4b0000b8e7a6449a924fe0212093b9f3936ef80cc8fdfbb770baad58f58b8c2c/68747470733a2f2f6e6573746a732e636f6d2f696d672f6c6f676f2d736d616c6c2e737667" width="120" alt="Nest Logo"&gt;&lt;/a&gt;
&lt;/p&gt;


&lt;p&gt;A progressive &lt;a href="https://nodejs.org" rel="nofollow noopener noreferrer"&gt;Node.js&lt;/a&gt; framework for building efficient and scalable server-side applications.&lt;/p&gt;
&lt;br&gt;
    &lt;p&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/~nestjscore" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/24dfd27aa1b2b7b9b523f5eaf2c6abf33084588f7f567553ad9e4b36113b5717/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f406e6573746a732f636f72652e737667" alt="NPM Version"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/~nestjscore" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b7c951e242d9686b460a9eab8b265d7240f84b29a79c299c648aa95d64bf8440/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f406e6573746a732f636f72652e737667" alt="Package License"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/~nestjscore" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7b83739222090e241d71c5fd4938703c7dedfafef0cde0d96022c3cf9b3a57ca/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f406e6573746a732f636f6d6d6f6e2e737667" alt="NPM Downloads"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://circleci.com/gh/nestjs/nest" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/90e78bdb27156e5275cdb3028402d4cc16b313c300b8dfdadd865455164d68ad/68747470733a2f2f696d672e736869656c64732e696f2f636972636c6563692f6275696c642f6769746875622f6e6573746a732f6e6573742f6d6173746572" alt="CircleCI"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://discord.gg/G7Qnnhy" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/418492403803275197fbce1084b95b08d56ad9c7d2a0d6d3fa70dea12ff31284/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646973636f72642d6f6e6c696e652d627269676874677265656e2e737667" alt="Discord"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opencollective.com/nest#backer" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ebdc9e103775edc0db99103676102f341ba228170356d4e069dfef64ef635593/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6e6573742f6261636b6572732f62616467652e737667" alt="Backers on Open Collective"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opencollective.com/nest#sponsor" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e95a1e851cf02fe970fce3fd496498c907a566aef7b32edbe699fb701e1fdbc/68747470733a2f2f6f70656e636f6c6c6563746976652e636f6d2f6e6573742f73706f6e736f72732f62616467652e737667" alt="Sponsors on Open Collective"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;a href="https://paypal.me/kamilmysliwiec" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4f9ed737abe81e3e0c3278f57f87fe09674513cb858c4a7dd0712c795e75c39b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f6e6174652d50617950616c2d6666336635392e737667"&gt;&lt;/a&gt;&lt;br&gt;
    &lt;a href="https://opencollective.com/nest#sponsor" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fab509818f8e438f1f2e4d7b42baf9d12b6bf45b2ad80fd338a764334867bf47/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f537570706f727425323075732d4f70656e253230436f6c6c6563746976652d3431423838332e737667" alt="Support us"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;a href="https://twitter.com/nestframework" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e984f5b62ec34062df9b35352b3c756486e5b83f9dc33d14116286cd40f5f071/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f6e6573746672616d65776f726b2e7376673f7374796c653d736f6369616c266c6162656c3d466f6c6c6f77"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Nest is a framework for building efficient, scalable &lt;a href="https://nodejs.org" rel="nofollow noopener noreferrer"&gt;Node.js&lt;/a&gt; server-side applications. It uses modern JavaScript, is built with &lt;a href="https://www.typescriptlang.org" rel="nofollow noopener noreferrer"&gt;TypeScript&lt;/a&gt; (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).&lt;/p&gt;

&lt;p&gt;Under the hood, Nest makes use of &lt;a href="https://expressjs.com/" rel="nofollow noopener noreferrer"&gt;Express&lt;/a&gt;, but also provides compatibility with a wide range of other libraries, like &lt;a href="https://github.com/fastify/fastify" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt;, allowing for easy use of the myriad of third-party plugins which are available.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Philosophy&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications, giving rise to awesome projects like &lt;a href="https://angular.io/" rel="nofollow noopener noreferrer"&gt;Angular&lt;/a&gt;, &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;React&lt;/a&gt;, and &lt;a href="https://github.com/vuejs/vue" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;, which improve developer productivity and enable the construction of fast, testable, and extensible frontend applications. However, on the server-side, while there are a lot of superb libraries…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nestjs/nest" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/facebook" rel="noopener noreferrer"&gt;
        facebook
      &lt;/a&gt; / &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;
        react
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The library for web and native user interfaces.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
&lt;a href="https://react.dev/" rel="nofollow noopener noreferrer"&gt;React&lt;/a&gt; · &lt;a href="https://github.com/facebook/react/blob/main/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6581c31c16c1b13ddc2efb92e2ad69a93ddc4a92fd871ff15d401c4c6c9155a4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="GitHub license"&gt;&lt;/a&gt; &lt;a href="https://www.npmjs.com/package/react" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9b33f253eb1c389ad196feb8b398d00d23fad5de7391fb9bb1f951fd405b62bd/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f72656163742e7376673f7374796c653d666c6174" alt="npm version"&gt;&lt;/a&gt; &lt;a href="https://github.com/facebook/react/actions/workflows/runtime_build_and_test.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/facebook/react/actions/workflows/runtime_build_and_test.yml/badge.svg" alt="(Runtime) Build and Test"&gt;&lt;/a&gt; &lt;a href="https://github.com/facebook/react/actions/workflows/compiler_typescript.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/facebook/react/actions/workflows/compiler_typescript.yml/badge.svg?branch=main" alt="(Compiler) TypeScript"&gt;&lt;/a&gt; &lt;a href="https://legacy.reactjs.org/docs/how-to-contribute.html#your-first-pull-request" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d88d8d77fa79e828eea397f75a1ebd114d13488aeec4747477ffbd2274de95ed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e737667" alt="PRs Welcome"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;React is a JavaScript library for building user interfaces.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Declarative:&lt;/strong&gt; React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component-Based:&lt;/strong&gt; Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep the state out of the DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn Once, Write Anywhere:&lt;/strong&gt; We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using &lt;a href="https://nodejs.org/en" rel="nofollow noopener noreferrer"&gt;Node&lt;/a&gt; and power mobile apps using &lt;a href="https://reactnative.dev/" rel="nofollow noopener noreferrer"&gt;React Native&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://react.dev/learn" rel="nofollow noopener noreferrer"&gt;Learn how to use React&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Some other open source packages that I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mongoose&lt;/li&gt;
&lt;li&gt;Graphql&lt;/li&gt;
&lt;li&gt;apollo server &amp;amp; client &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deployment is powered by heroku and netlify. &lt;/p&gt;

&lt;p&gt;Hope you like what I've built!&lt;/p&gt;

</description>
      <category>atlashackathon</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Step 3: Setting up Storybook with React Native Web: show your mobile components the browser!</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Sat, 31 Oct 2020 05:52:58 +0000</pubDate>
      <link>https://dev.to/ugglr/step-3-setting-up-storybook-with-react-native-web-show-your-mobile-components-the-browser-12ke</link>
      <guid>https://dev.to/ugglr/step-3-setting-up-storybook-with-react-native-web-show-your-mobile-components-the-browser-12ke</guid>
      <description>&lt;p&gt;In the last part of this series it's finally time to use what we installed in the first two parts and use everything together!&lt;/p&gt;

&lt;p&gt;If you have not been following along please go and have a look at the first parts in this series!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;setup react native &amp;amp; @storybook/react-native&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-1-setting-up-react-native-with-storybook-36l"&gt;Step 1: Setting up React Native with Storybook&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup react from scratch together with react native web&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-2-setting-up-react-with-react-native-web-30ba"&gt;Step 2: Setting up react with react native web&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup @storybook/react + react native web to run as a parallel storybook&lt;/td&gt;
&lt;td&gt;You are here now!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Starting point
&lt;/h1&gt;

&lt;p&gt;To just do a quick recap I want to state where we are at at this point in our journey. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After &lt;strong&gt;Step 1&lt;/strong&gt;, was completed we had a running React Native project with Storybook installed. It means when we run the code we have a storybook installation, which listens to the storybook development server for react native. Further we have react-native-storyloader set up. It loads our Storybook stories files for us when we run the dev command.&lt;/li&gt;
&lt;li&gt;After &lt;strong&gt;Step 2&lt;/strong&gt;, we have in parallel a detached vanilla React project set up, with it's own webpack configuration, which is also using react native web.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So! what do we do now?! 🤷‍♂️&lt;/p&gt;

&lt;h1&gt;
  
  
  Manually installing Storybook for React.js 🤸‍♂️
&lt;/h1&gt;

&lt;p&gt;For our repos web alter ego React.js installation we need to install Storybook, and since this was initiated as a React Native project we need to do that &lt;strong&gt;manually&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's pretty straight forward and is described well in the storybook docs here: &lt;a href="https://storybook.js.org/docs/react/get-started/install" rel="noopener noreferrer"&gt;Storybook Docs: React.js Guide&lt;/a&gt;. &lt;strong&gt;Edit: WAS well described&lt;/strong&gt; They changes the docs....&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's go through the steps:&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1.) at the root run the command in your terminal: 🚀
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx sb init &lt;span class="nt"&gt;--type&lt;/span&gt; react &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--type react&lt;/code&gt; tells the Storybook CLI to install stuff for a react project&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-f&lt;/code&gt; Forces the installation, because the CLI will detect the react native installation and abort the installation without the face flag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If everything completes properly you will see a newly created &lt;code&gt;.storybook&lt;/code&gt; folder in the root of you project and a &lt;code&gt;.stories&lt;/code&gt; folder added to your &lt;code&gt;.src&lt;/code&gt; folder. Further it added a couple of scripts, and &lt;code&gt;@storybook/react&lt;/code&gt; + &lt;code&gt;react-is&lt;/code&gt; packages was installed + added to your devDependencies in your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.) Add our scripts to &lt;code&gt;package.json&lt;/code&gt; 🚀
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;It's a habit of mine to add scripts first, because it reminds me of what I'm trying to accomplish. All this work is because I want to run a script and something should happen right. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Storybook CLI might overwrite some of the scripts already present in your &lt;code&gt;package.json&lt;/code&gt;, I fiddled around a bit and landed on this final version for my scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"android"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn run prestorybook &amp;amp;&amp;amp; react-native run-android"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn run prestorybook &amp;amp;&amp;amp; react-native run-ios"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-native start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prestorybook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rnstl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"storybook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"start-storybook -p 7007"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build-react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack --mode production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start-react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack-dev-server --config ./webpack.config.js --mode development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start-storybook-web"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./node_modules/@storybook/react/bin/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build-storybook-web"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./node_modules/@storybook/react/bin/build.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"storybook-web"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn run start-storybook-web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one we are focusing on right now are the &lt;code&gt;start-storybook-web&lt;/code&gt;, &lt;code&gt;build-storybook-web&lt;/code&gt; and &lt;code&gt;storybook-web&lt;/code&gt;. The previous scripts we covered in the first two steps in the series.&lt;/p&gt;

&lt;h2&gt;
  
  
  3.) [Optional] Test our React.js Storybook installation before modifying it. 🚀
&lt;/h2&gt;

&lt;p&gt;At this point we already have React Native component(s) inside of &lt;code&gt;src/components&lt;/code&gt; and they cannot be rendered by Storybook as it is right now. To see that error in action you can right now run the script, by typing this command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn start-storybook-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error looks like this for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ERROR &lt;span class="k"&gt;in&lt;/span&gt; ./node_modules/react-native-swipe-gestures/index.js 121:11
Module parse failed: Unexpected token &lt;span class="o"&gt;(&lt;/span&gt;121:11&lt;span class="o"&gt;)&lt;/span&gt;
You may need an appropriate loader to handle this file &lt;span class="nb"&gt;type&lt;/span&gt;, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However we can try our installation on the test components the Storybook CLI added for a React.js project inside of &lt;code&gt;src/stories&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;so open the file &lt;code&gt;.storybook/main.js&lt;/code&gt; and change the stories array &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/**/*.stories.mdx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/**/*.stories.@(js|jsx|ts|tsx)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;To&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/stories/**/*.stories.mdx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/stories/**/*.stories.@(js|jsx|ts|tsx)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn start-storybook-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and it should compile! Behold! 🥳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F23feu7xfew1763q7lir8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F23feu7xfew1763q7lir8.png" alt="React.js Storybook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4.) Adding our React Native Stories to Storybook 🚀
&lt;/h2&gt;

&lt;p&gt;Close any instances and let's start adding our react native stories to our Storybook React.js setup. &lt;/p&gt;

&lt;p&gt;Again let's modify &lt;code&gt;.storybook/main.js&lt;/code&gt; to load our React Native written components and &lt;code&gt;*.stories.js&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From the above stories configuration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/stories/**/*.stories.mdx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/stories/**/*.stories.@(js|jsx|ts|tsx)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;To&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;stories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/components/**/*.stories.[tj]s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note that I removed the .mdx files, I don't use that&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Again, running the &lt;code&gt;yarn start-storybook-web&lt;/code&gt; script will result in an error, because we have not configured the React.js Storybook installation to use React Native Web yet in a custom Webpack config. &lt;/p&gt;

&lt;p&gt;so let's do that!&lt;/p&gt;

&lt;p&gt;5.) Add a custom Webpack configuration to Storybook 🚀&lt;/p&gt;

&lt;p&gt;Storybook already comes with a Webpack configuration which we don't really want to modify, but rather inject our own stuff into. And since we already what we want to configure, as described in Step 2 of the series, where we got React Native Web working with React.js, we have &lt;strong&gt;ALMOST&lt;/strong&gt; all the stuff we want to inject into the Storybook webpack configuration already prepared. (We are missing one alias soon to be described)&lt;/p&gt;

&lt;h3&gt;
  
  
  So where do we inject our stuff?
&lt;/h3&gt;

&lt;p&gt;open &lt;code&gt;.storybook/main.js&lt;/code&gt; and at the top of the file import our webpack configuration like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;custom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../webpack.config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then in the &lt;code&gt;module.exports = { ... }&lt;/code&gt; add an entry called &lt;code&gt;webpackFinal&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;custom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../webpack.config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;stories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/components/**/*.stories.[tj]s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;webpackFinal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alias&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way we don't overwrite, or destroy the Webpack configuration that Storybook already comes with, but rather we inject our own &lt;code&gt;alias&lt;/code&gt; rules and our own &lt;code&gt;module.rules&lt;/code&gt; into it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: yes yes I removed the addons array&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Also let's not forget that we need to modify our &lt;code&gt;webpack.config.js&lt;/code&gt; because we want atleast more things in our aliases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;all &lt;code&gt;@storybook/react-native&lt;/code&gt; imports should resolve to &lt;code&gt;@storybook/react&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;because in the React Native side we are always using the import from &lt;code&gt;@storybook/react&lt;/code&gt; native and obviously that's not what we want on the web side of Storybook. First the component go through &lt;code&gt;React Native Web&lt;/code&gt; so there is no trace left of React Native Code in them after being compiled, and then we want to run Storybook as "normal" on them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html-webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPluginConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HTMLWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./public/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.web.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-here&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;js$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/node_modules&lt;/span&gt;&lt;span class="se"&gt;\/(?!()\/)&lt;/span&gt;&lt;span class="sr"&gt;.*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/preset-env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/preset-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;HTMLWebpackPluginConfig&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;devServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;historyApiFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contentBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and if that is super confusing to you please read Step 2, where I try my best to explain the webpack part 😅&lt;/p&gt;

&lt;p&gt;Let's try our &lt;code&gt;yarn start-storybook-web&lt;/code&gt; script again and see if it runs!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn start-storybook-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀🚀🚀🚀🚀🚀 BEHOOOLD! 🚀🚀🚀🚀🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F63ohdjc7za7rr3f7enqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F63ohdjc7za7rr3f7enqb.png" alt="Storybook web running react native components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Styled components to webpack
&lt;/h2&gt;

&lt;p&gt;Just for the ones of us that want's to use styled components when we create our react native components, add this line to your aliases in the webpack config and it should hook right in 👨‍💻&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components/native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so aliases look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components/native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Fin!
&lt;/h1&gt;

&lt;p&gt;Hope this was educational and a little cool! &lt;/p&gt;

&lt;p&gt;Now you can host a static website with your React Native components, or you can actually develop them in a browser without firing up a simulator / emulator. Which is really niiiiiiice, especially if you are running on an older machine!&lt;/p&gt;

&lt;p&gt;See the full repo here! --&amp;gt; &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate" rel="noopener noreferrer"&gt;Github: react-native-storybook-boilerplate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I got it hosted on Netlify, and again, the components are all written in React Native syntax!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rn-sb-boilerplate.netlify.app/" rel="noopener noreferrer"&gt;Hosted Boilerplate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other parts again!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Series: The ultimate react native ui library starter repo&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/series-the-ultimate-react-native-ui-library-starter-repo-bho"&gt;Step 0 link&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step 1: Setting up react native with Storybook&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-1-setting-up-react-native-with-storybook-36l"&gt;Step 1 link&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step 2: Setting up react with react native web&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-2-setting-up-react-with-react-native-web-30ba"&gt;Step 2 link&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Thanks! 🎉
&lt;/h1&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Publish/Update NPM packages with GitHub Actions</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Tue, 15 Sep 2020 14:58:40 +0000</pubDate>
      <link>https://dev.to/ugglr/publish-update-npm-packages-with-github-actions-1m8l</link>
      <guid>https://dev.to/ugglr/publish-update-npm-packages-with-github-actions-1m8l</guid>
      <description>&lt;p&gt;Ever had an NPM package that never get's updated even though you make changes from time to time. I do! which I talked about in a previous post: &lt;a href="https://dev.to/ugglr/cross-platform-react-native-scroll-picker-component-3oh8"&gt;cross-platform-react-native-scroll-picker-component&lt;/a&gt;. It's time to make my life just slightly easier and automate the publish step with Github Actions.&lt;/p&gt;

&lt;p&gt;Since the release of GitHub Actions everyone I know have been raving about them, so In an attempt to learn a little bit, and solve a problem I have, I thought I could try it out :)&lt;/p&gt;

&lt;p&gt;oh and here's the official GitHub Actions docs: &lt;a href="https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow" rel="noopener noreferrer"&gt;GH Actions Docs&lt;/a&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  Goal
&lt;/h1&gt;

&lt;p&gt;It's important to know what you want to do, before starting configuring (or.. doing anything, really!). For me it's going to be something quite simple, but very useful. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is my starting point and what I want to achieve:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I have an open source package which is published to NPM 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/react-native-value-picker" rel="noopener noreferrer"&gt;NPM: react-native-value-picker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ugglr/react-native-value-picker" rel="noopener noreferrer"&gt;Github: react-native-value-picker&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When I make a new "official" &lt;code&gt;release&lt;/code&gt; on Github I want to update / re-publish this package, so my updates go live.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To do this manually we need to login in and publish/re-publish through the NPM CLI, something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Authenticating with npm&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm login

&lt;span class="c"&gt;# Publish the package&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm publish


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

&lt;/div&gt;

&lt;p&gt;I know, I know, it's not a massive amount of work to do those two steps each time I want to push out an update to the package, but we are learning something here.&lt;/p&gt;

&lt;p&gt;Prior to GitHub Actions in order to automate this task, I would have needed to involve a third party CI/CD solution, and on top, it's free. &lt;/p&gt;

&lt;p&gt;So let's get started with the config.&lt;/p&gt;

&lt;h1&gt;
  
  
  Preparing our repo to use GitHub Actions
&lt;/h1&gt;

&lt;p&gt;The execution chains or jobs which we want to run inside of our GitHub Actions are called &lt;code&gt;workflows&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So GitHub will look inside &lt;code&gt;.github/workflows&lt;/code&gt; for workflows / execution chains so let's make a &lt;code&gt;.github&lt;/code&gt; folder inside of our root, this folder is common if there are special configurations to the repository, like code owners. Further we need to make a folder inside our &lt;code&gt;.github&lt;/code&gt; folder called &lt;code&gt;workflows&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;When all is done you'll have a a &lt;code&gt;root/.github/workflows&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Like most CI/CD solutions GitHub Actions &lt;code&gt;workflows&lt;/code&gt; are configured using a &lt;code&gt;.yml&lt;/code&gt; file, and we need to put that that file into the &lt;code&gt;workflow&lt;/code&gt; folder we created above.  I named my yml-file &lt;code&gt;npm-publish.yml&lt;/code&gt; and here's a badly made folder-tree to make it more clear. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

---&amp;gt; root
|   ---&amp;gt; .github
|      ----&amp;gt; workflows
|          ----&amp;gt; npm-publish.yml // contains our workflows.
| ----&amp;gt; rest of app


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

&lt;/div&gt;
&lt;h1&gt;
  
  
  Configuring our workflow
&lt;/h1&gt;

&lt;p&gt;So inside of our &lt;code&gt;npm-publish.yml&lt;/code&gt; we are good to go configuring our workflow. I'll post the finished thing first and then I'll go through it step by step what it does. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Npm Publish&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;published&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
          &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://registry.npmjs.org/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm publish --access public&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;NODE_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{secrets.NPM_AUTH_TOKEN}}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Let's break it down&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Npm Publish&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Giving the workflow a name, at the very top we give the encompassing workflow a name that makes sense to us, you are free to name it anything you'd like :)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

on:
  release:
    types: [published]


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;on&lt;/code&gt;-keyword tells GitHub when the workflow is going to run, in this case I specify that I want it to run when there is a new release, and more specifically I want it when the release type is &lt;code&gt;published&lt;/code&gt;. This is important and required because releases could also be &lt;code&gt;updated&lt;/code&gt; or &lt;code&gt;deleted&lt;/code&gt;. This makes sure that we run on &lt;code&gt;release publish&lt;/code&gt; only. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;jobs&lt;/code&gt; keyword tells our CI the different steps we want to execute. &lt;/p&gt;

&lt;p&gt;In this case I want to &lt;code&gt;build&lt;/code&gt; the project, on the latest version of Ubuntu, so that is specified as &lt;code&gt;ubuntu-latest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Further we need to define the steps within our job: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

   &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
          &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://registry.npmjs.org/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm publish --access public&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Inside of our job we are now defining the steps, We already defined the operating system of our virtual machine / box, so we are at the same stage as when we run the project locally on our computer. &lt;/p&gt;

&lt;p&gt;Well, in plain English, what do we do locally when we run a project like this?&lt;/p&gt;

&lt;p&gt;Normally it would look something like this in our terminal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Clone our project&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git:repo-address


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Install all packages / dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. do the publishing steps&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;npm login
&lt;span class="nv"&gt;$ &lt;/span&gt;npm Publish


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

&lt;/div&gt;

&lt;p&gt;Locally we already have our development environment setup, we already have node, yarn, etc. But because we are essentially creating a new computer on Githubs servers running Ubuntu we need to be more specific, and that's what we are doing in the configuration file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Clone the repo.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

- uses: actions/checkout@v2


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Install node on a known working version, Specify what package registry we want to use.&lt;/strong&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    - uses: actions/setup-node@v1
        with:
          node-version: 12
          registry-url: https://registry.npmjs.org/


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. Install dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

- run: yarn install


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4. Publish to NPM&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

- run: npm publish --access public


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;5. Further since there is no human sitting and looking at the script to authenticate us by passing in username and password, we need to pass a &lt;code&gt;pre-authenticated&lt;/code&gt; token to our node environment&lt;/strong&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

        env:
          NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}}


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

&lt;/div&gt;

&lt;p&gt;And that's our new Github Action workflow configuration all done 🎉 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hold on! you might say, what about that NPM Auth token thingy?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's get that configured next. &lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring Auth tokens
&lt;/h1&gt;

&lt;p&gt;As I described earlier we need a pre-authenticated token to pass into our node environment. This is the way we authenticate towards NPM, and it's not very complicated to setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never put your token into the configuration file, it should be kept private&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I presume you have an account on npmjs.org if you are interested in following along.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Head on over to your account in npm and in the quick account menu press &lt;code&gt;Auth Tokens&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw0qy2au5buckxif56pct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw0qy2au5buckxif56pct.png" alt="npm menu picture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;Auth Token&lt;/code&gt; page you'll want to create a new Token. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxl8hsmk3qqqir9enyzen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxl8hsmk3qqqir9enyzen.png" alt="create new token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will then be prompted if you want to grant the token &lt;code&gt;read and publish&lt;/code&gt; or just &lt;code&gt;read&lt;/code&gt;, for the purpose in this case we need to have publishing rights, so read and publish it is. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkv1qky2sgt4rc465idl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkv1qky2sgt4rc465idl3.png" alt="npm permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the token has been created copy it, and make sure you can keep it with you for a little while until we add it into our repository secrets. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding NPM token to our repository
&lt;/h2&gt;

&lt;p&gt;Head over to your GitHub repository where your package exists and go to the settings page. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9xyzgbzo5bgqmdlaix0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9xyzgbzo5bgqmdlaix0v.png" alt="github settings menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside of settings head on over to the secrets sub-page. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvp9zm3ukfzgzv15ygv3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvp9zm3ukfzgzv15ygv3e.png" alt="secret sub menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Create a new Secret&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flyqjhe1o8lot806odp9u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flyqjhe1o8lot806odp9u.png" alt="new secret button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And in here you'll want to match the name of the token with what we wrote in our action configuration file. &lt;/p&gt;

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

&lt;p&gt;In our case we named our secret variable reference &lt;code&gt;NPM_AUTH_TOKEN&lt;/code&gt; and then you'll want to paste the token you got from NPM in the value field. &lt;/p&gt;

&lt;p&gt;When everything is well and done we will have it added. &lt;/p&gt;

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

&lt;p&gt;That's all we need for configuration, commit it, merge into master and let's try it out to see if it works.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing it out
&lt;/h1&gt;

&lt;p&gt;So, to test our newly created workflow we need to make a new release (published), since that what we configured it to trigger on. &lt;/p&gt;

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

&lt;p&gt;It does not really matter what you tag you choose for the release, but make sure the that the pre-release checkbox is &lt;strong&gt;not&lt;/strong&gt; checked. And you bumped the version in &lt;code&gt;package.json&lt;/code&gt;, NPM requires us to update the version when we publish changes.&lt;/p&gt;

&lt;p&gt;When the release is done let's head on over to our repository's action tab and see if we have something running!&lt;/p&gt;

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

&lt;p&gt;there we go, microphone drop.&lt;/p&gt;

&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;If you like to visit the repo I've been working in it's available right here: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ugglr/react-native-value-picker/actions" rel="noopener noreferrer"&gt;ugglr/react-native-value-picker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The package is available through NPM:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-native-value-picker" rel="noopener noreferrer"&gt;NPM: react-native-value-picker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the creation of that package was part of a previous post right here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/ugglr/cross-platform-react-native-scroll-picker-component-3oh8"&gt;DEV.to Cross platform react native scroll picker&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks for reading!
&lt;/h3&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Step 2: Setting up React with React-Native-Web</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Thu, 13 Aug 2020 04:31:50 +0000</pubDate>
      <link>https://dev.to/ugglr/step-2-setting-up-react-with-react-native-web-30ba</link>
      <guid>https://dev.to/ugglr/step-2-setting-up-react-with-react-native-web-30ba</guid>
      <description>&lt;h2&gt;
  
  
  In our pursuit of creating the ultimate UI development starting point, it is time to take the first step with react-native-web
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the second part of a series where I go through all the steps of creating &lt;a href="https://dev.to/ugglr/series-the-ultimate-react-native-ui-library-starter-repo-bho"&gt;The Ultimate React Native UI Library starter repo&lt;/a&gt;. Please visit the first post (just linked 👆🏻) for a general description of what we are trying to accomplish and where all the Steps are numbered + linked. &lt;/p&gt;

&lt;p&gt;The finished source code can be found here &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate"&gt;react-native-storybook-boilerplate&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The other parts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;setup react native &amp;amp; @storybook/react-native&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-1-setting-up-react-native-with-storybook-36l"&gt;Step 1: Setting up React Native with Storybook&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup react from scratch together with react native web&lt;/td&gt;
&lt;td&gt;You are here now!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup @storybook/react + react native web to run as a parallel storybook&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-3-setting-up-storybook-with-react-native-web-show-your-mobile-components-the-browser-12ke"&gt;Step 3: Setting up storybook with react native web: Show your mobile components in a browser&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  What's covered in this post? -&amp;gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;setting up react from scratch

&lt;ul&gt;
&lt;li&gt;installation&lt;/li&gt;
&lt;li&gt;webpack&lt;/li&gt;
&lt;li&gt;babel&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;setting up react-native-web

&lt;ul&gt;
&lt;li&gt;installation&lt;/li&gt;
&lt;li&gt;webpack alias configuration&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Please note that this is not a webpack or babel tutorial so I will more or less not cover the basics of those&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want to go really in depth in how to set up React from scratch I really recommend a tutorial series from &lt;a href="https://www.codecademy.com"&gt;codecademy&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.codecademy.com/articles/react-setup-i"&gt;React Setup Part 1: React and ReactDOM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codecademy.com/articles/react-setup-ii"&gt;React Setup Part 2: Babel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codecademy.com/articles/react-setup-iii"&gt;React Setup Part 3: Webpack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codecademy.com/articles/react-setup-iv"&gt;React Setup Part 4: HTMLWebpackPlugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codecademy.com/articles/react-setup-v"&gt;React Setup Part 5: Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I thought that series was very good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up React - Installing our dependencies
&lt;/h2&gt;

&lt;p&gt;If you are following along from the first part in the series you have a "normal" &lt;code&gt;react-native&lt;/code&gt; and &lt;code&gt;storbook&lt;/code&gt; already set up and running locally, and now it's time to add &lt;code&gt;React&lt;/code&gt; into the mix. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obviously we need react, but it comes with the react-native installation but we need to add &lt;code&gt;react-dom&lt;/code&gt; -&amp;gt;&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-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then we need to install our babel dependencies babel&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 --dev @babel/core babel-loader @babel/preset-react @babel/preset-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we also need to ochestrate the packaging so let's install webpack also while we are at it:&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 --dev webpack webpack-cli webpack-dev-server html-webpack-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add scripts to package.json
&lt;/h2&gt;

&lt;p&gt;You can do this in any order you like but, I for some reason, like to add scripts first. I think it gives me a sense of what I'm trying to acomplish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build-react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack --mode production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start-react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webpack-dev-server --config ./webpack.config.js --mode development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You obviously can name the scripts anything you like &amp;amp; makes sense to you: I named my scripts &lt;code&gt;start-react&lt;/code&gt; &amp;amp; &lt;code&gt;build-react&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Webpack
&lt;/h2&gt;

&lt;p&gt;This is where the magic happens 🤹🏻‍♀️ In the root folder add a &lt;code&gt;webpack.config.js&lt;/code&gt; file and add the folowing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html-webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPluginConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./public/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.web.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;js$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/node_modules&lt;/span&gt;&lt;span class="se"&gt;\/(?!()\/)&lt;/span&gt;&lt;span class="sr"&gt;.*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/preset-env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@babel/preset-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;HTMLWebpackPluginConfig&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;devServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;historyApiFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contentBase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;for a better description of what's going on I really recommend this article from &lt;code&gt;codecademy&lt;/code&gt; &lt;a href="https://www.codecademy.com/articles/react-setup-iii"&gt;React Setup, Part III: Webpack&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a rough description:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;entry&lt;/th&gt;
&lt;th&gt;what it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;entry&lt;/td&gt;
&lt;td&gt;Tells Webpack the root file of our application. Starting from that file it will go through the whole tree and transform all code which match our webpack rules. I've named this file &lt;code&gt;index.web.js&lt;/code&gt; we need to remember to create this file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;output&lt;/td&gt;
&lt;td&gt;Configuration for the output files from react. &lt;code&gt;filename&lt;/code&gt; gives the packed javascript a name. &lt;code&gt;path&lt;/code&gt; sets an output folder for the packed files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rules&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;test&lt;/code&gt; is a regular expression which matches to our source files, i.e. &lt;code&gt;*.js&lt;/code&gt;. &lt;code&gt;exclude&lt;/code&gt; excludes files we don't want webpack to touch. &lt;code&gt;use&lt;/code&gt; this is where we plug in &lt;code&gt;babel&lt;/code&gt; i.e. the stuff that will transform our react code into vanilla js.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After webpack are dont with the JS it needs to make a new HTML file as well, that's where &lt;code&gt;HTMLWebpackPluginConfig&lt;/code&gt; comes in, please refer to this article for a better description: &lt;a href="https://www.codecademy.com/articles/react-setup-iv"&gt;React Setup, Part IV: HTMLWebpackPlugin&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Let's take a look at the code for the &lt;code&gt;HTMLWebpackPlugin&lt;/code&gt; closer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPluginConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HTMLWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./public/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;template&lt;/code&gt;: It tells our plugin what template file it should use and copy to our &lt;code&gt;./build&lt;/code&gt; folder. I set it to a file in the folder &lt;code&gt;public&lt;/code&gt; and the file name is &lt;code&gt;index.html&lt;/code&gt;. (We shall not forget to create these.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filename&lt;/code&gt;: Is the name of the newly created file which it copies. As I mentioned above this file will wind up in &lt;code&gt;./build&lt;/code&gt; folder. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;inject&lt;/code&gt;: Is where the our JavaScript script tag will be injected. Both &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; are valid options. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What's the &lt;code&gt;path&lt;/code&gt; stuff?&lt;/strong&gt;&lt;br&gt;
It's just a way to concatenate path-strings instead of using a &lt;code&gt;+&lt;/code&gt;sign, &lt;code&gt;__dirname&lt;/code&gt; meaning the current directory which the file is in. &lt;/p&gt;
&lt;h2&gt;
  
  
  Add entry files
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Add public &lt;code&gt;index.html&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;As I've configured the &lt;code&gt;HTMLWebpackPlugin&lt;/code&gt;, and shortly explained right above, we need to add a &lt;code&gt;index.html&lt;/code&gt; into a folder called &lt;code&gt;public&lt;/code&gt;,&lt;/p&gt;

&lt;p&gt;So! In &lt;code&gt;root&lt;/code&gt; create a folder called &lt;code&gt;public&lt;/code&gt; and inside of that folder create a file called &lt;code&gt;index.html&lt;/code&gt; and the following &lt;code&gt;html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;React Native Web Storybook&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take notice of the &lt;code&gt;id&lt;/code&gt;-name (&lt;code&gt;app&lt;/code&gt;) of the div where we are injecting the react single page application. All of these files are &lt;code&gt;react&lt;/code&gt; boilerplate which are basically the same when using the library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add index.web.js
&lt;/h3&gt;

&lt;p&gt;In the root add &lt;code&gt;index.web.js&lt;/code&gt; and code the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;this is where &lt;code&gt;&amp;lt;div id="app"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; needs to match &lt;code&gt;document.getElementById('app')&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've used &lt;code&gt;create-react-app&lt;/code&gt; before you'll see that it's basically the same code as they generate for you, in our case I wan't to keep &lt;code&gt;web react&lt;/code&gt; seperate from &lt;code&gt;react-native&lt;/code&gt; so I named the file with the extension &lt;code&gt;.web.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From the code we also see that we need to add our &lt;code&gt;&amp;lt;App /&amp;gt;&lt;/code&gt; component, so let's do that next:&lt;/p&gt;

&lt;h3&gt;
  
  
  Add App.web.js
&lt;/h3&gt;

&lt;p&gt;In the root add &lt;code&gt;App.web.js&lt;/code&gt;, this will be the entry component for react, and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see this is normal jsx, we will come to adding &lt;code&gt;react-native-web&lt;/code&gt; after we confirm that our &lt;code&gt;vanilla react&lt;/code&gt; setup works first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test our React configuration
&lt;/h2&gt;

&lt;p&gt;It's time to check if we are able to run everything together so let's run our script:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Hopefully this starts the Webpack development server for you and you see this page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Aw0hivWd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/za0y648fexxkib3elnck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Aw0hivWd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/za0y648fexxkib3elnck.png" alt="react hello world" width="880" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Great Success Time to add React-Native-Web into the configuration!
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Install React-Native-Web
&lt;/h2&gt;

&lt;p&gt;For those who are not quite familiar &lt;code&gt;react-native-web&lt;/code&gt; makes it possible to use the &lt;code&gt;react-native-api&lt;/code&gt; to write components for the web. It transforms &lt;code&gt;View&lt;/code&gt; to &lt;code&gt;div&lt;/code&gt; etc. so it's readable by a web browser. Really cool stuff!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"React Native for Web" makes it possible to run React Native components and APIs on the web using React DOM.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's open source and do check it out!&lt;br&gt;
&lt;a href="https://github.com/necolas/react-native-web"&gt;react-native-web&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react-native-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When that's done we need to modify our &lt;code&gt;webpack&lt;/code&gt; configuration so it swaps out all our &lt;code&gt;react-native&lt;/code&gt; imports for &lt;code&gt;react-native-web&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Re-configure webpack.config.js
&lt;/h3&gt;

&lt;p&gt;so it our awesome webpack file let's add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's enough configuration for now!&lt;/p&gt;

&lt;p&gt;Let's modify our &lt;code&gt;App.web.js&lt;/code&gt; to use the &lt;code&gt;react-native-api&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="nx"&gt;native&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;run yet again:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;and BEHOLD!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FipuL4hl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sg5z3je51vana9p0flvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FipuL4hl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sg5z3je51vana9p0flvw.png" alt="react native hello world" width="880" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this we can now use the whole &lt;code&gt;react-native&lt;/code&gt;-api for the web, you can have a look here: &lt;a href="https://reactnative.dev/docs/components-and-apis"&gt;React-Native: Core Components and APIs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To extra check this we can, for instance, add an &lt;code&gt;&amp;lt;ActivityIndicator /&amp;gt;&lt;/code&gt; component to our &lt;code&gt;App.web.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ActivityIndicator&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="nx"&gt;native&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ActivityIndicator&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's the result!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_SKfKcWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/skj0g5ecpoulg94xb0jn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_SKfKcWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/skj0g5ecpoulg94xb0jn.png" alt="activity indicator" width="880" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it for this part in the series!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading and again, you can find the finished project here: &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate"&gt;react-native-storybook-boilerplate&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Step 1: Setting up React Native with Storybook</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Sun, 02 Aug 2020 03:18:18 +0000</pubDate>
      <link>https://dev.to/ugglr/step-1-setting-up-react-native-with-storybook-36l</link>
      <guid>https://dev.to/ugglr/step-1-setting-up-react-native-with-storybook-36l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is the first post in a series of setting up a react native UI library development foundation. Please refer to the link collections here &lt;a href="https://dev.to/ugglr/series-the-ultimate-react-native-ui-library-starter-repo-bho"&gt;Series: The Ultimate React Native UI Library starter repo&lt;/a&gt; for the full series overview.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the first step of setting up the ultimate UI library boilerplate we go through making a new init, and installing Storybook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you've done this sort of thing before you'll probably want to jump to the bottom where I install a package which will load stories dynamically&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Oh right, I'm not using expo... ;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The other parts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;setup react native &amp;amp; @storybook/react-native&lt;/td&gt;
&lt;td&gt;You are here now!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup react from scratch together with react native web&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-2-setting-up-react-with-react-native-web-30ba"&gt;Step 2: Setting up react with react native web&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup @storybook/react + react native web to run as a parallel storybook&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-3-setting-up-storybook-with-react-native-web-show-your-mobile-components-the-browser-12ke"&gt;Step 3: Setting up storybook with react native web: Show your mobile components in a browser&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  React Native Init
&lt;/h2&gt;

&lt;p&gt;If you are completely new to react native please follow the steps on the &lt;a href="https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer"&gt;official react native docs&lt;/a&gt; to get your environment setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Init&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npx react-native init RNStorybook


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

&lt;/div&gt;

&lt;p&gt;This will set up a fresh new react native project for you. &lt;/p&gt;

&lt;p&gt;Make sure that the installation was successful by running both the android and iOS builds of the project before going ahead. I always take things step by step, so when things bug out then I know exactly where it worked and where it broke. &lt;/p&gt;

&lt;p&gt;so for the people who forgot etc. here's the commands for doing so. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cd ios &amp;amp;&amp;amp; pod install

cd .. 

yarn run ios


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

&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yarn run android


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

&lt;/div&gt;

&lt;p&gt;Behold the welcome screen!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Android&lt;/th&gt;
&lt;th&gt;iOS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flps57g4urh9yskl8dilo.png" alt="Alt Text"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1s4pm42llok7up3t3l10.png" alt="Alt Text"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Installing Storybook
&lt;/h2&gt;

&lt;p&gt;Using the automated setup as recommended by the docs here: &lt;a href="https://storybook.js.org/docs/guides/quick-start-guide/" rel="noopener noreferrer"&gt;Storybook quick-start guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;inside the root folder run the following command to initiate the installation: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npx -p @storybook/cli sb init


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When prompted if you want to install the react-native server accept.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After that open up your code editor and we will do the final steps in rendering storybook out on the screen.&lt;/p&gt;

&lt;p&gt;inside the folder &lt;code&gt;./storybook&lt;/code&gt; open up index.js and we will add in our app name. You can either add it manually or you can be lazy as me and import the app name from &lt;code&gt;app.json&lt;/code&gt; in the root folder. It has the benefit that if the app name changes you won't need to go in and change it manually. &lt;/p&gt;

&lt;p&gt;Below is the result:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./storybook/index.js&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppRegistry&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getStorybookUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../app.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./rn-addons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// import stories&lt;/span&gt;
&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./stories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Refer to https://github.com/storybookjs/storybook/tree/master/app/react-native#start-command-parameters&lt;/span&gt;
&lt;span class="c1"&gt;// To find allowed options for getStorybookUI&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StorybookUIRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStorybookUI&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;

&lt;span class="c1"&gt;// If you are using React Native vanilla and after installation you don't see your app name here, write it manually.&lt;/span&gt;
&lt;span class="c1"&gt;// If you use Expo you can safely remove this line.&lt;/span&gt;
&lt;span class="nx"&gt;AppRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;StorybookUIRoot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;StorybookUIRoot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;after we have added our app name to Storybook, inside of the root folder, we open &lt;code&gt;index.js&lt;/code&gt;. This is the default entry point for our React Native app. &lt;/p&gt;

&lt;p&gt;Inside of &lt;code&gt;./index.js&lt;/code&gt; comment everything out and add the following line:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./storybook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This will render storybook as the first entry to your app, but later if you want Storybook to be rendered inside of a tab-view or another type of screen you'll just add storybook as any other component. More on that in the Storybook docs. &lt;/p&gt;

&lt;p&gt;Now when you run the following command we can start up our &lt;code&gt;React Native&lt;/code&gt; development server on port &lt;code&gt;7007&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yarn run storybook


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

&lt;/div&gt;

&lt;p&gt;It will give you the following screen:&lt;/p&gt;

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

&lt;p&gt;Hold your horses you might say "That menu-bar never stops loading!" and you'll be right. This web interface is trying to connect to a iOS or Android emulator.&lt;/p&gt;

&lt;p&gt;so run an emulator and if you put the browser window and the device side by side it should look like:&lt;/p&gt;

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

&lt;p&gt;If you play around with this you notice that you can control the view which is being shown in the emulator / simulator from the browser. Neat right! ⭐️ It's a nice feature which makes navigating your component library on a device very fast and easy. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up dynamic story-loading
&lt;/h2&gt;

&lt;p&gt;As your project grows you don't want to add stories into storybook manually as is the default. It's tedious and you'll spent time "debugging" why your component does not show up. &lt;/p&gt;

&lt;p&gt;In comes &lt;a href="https://github.com/elderfo/react-native-storybook-loader" rel="noopener noreferrer"&gt;react-native-storybook-loader&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I really like this project because after setting it up I don't have to worry about adding any new stories every again. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yarn add -dev react-native-storybook-loader 


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Add script to package.json&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;......&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prestorybook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rnstl"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;......&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Add into Storybook configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;./storybook/index.js&lt;/code&gt; and modify the entry where the stories are loaded from:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./storybook/index.js&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppRegistry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getStorybookUI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;configure&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;appName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../app.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadStories&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./storyLoader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./rn-addons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Add React native storybook loader here!&lt;/span&gt;
&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;loadStories&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;------------------&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Refer to https://github.com/storybookjs/storybook/tree/master/app/react-native#start-command-parameters&lt;/span&gt;
&lt;span class="c1"&gt;// To find allowed options for getStorybookUI&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StorybookUIRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStorybookUI&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;

&lt;span class="c1"&gt;// If you are using React Native vanilla and after installation you don't see your app name here, write it manually.&lt;/span&gt;
&lt;span class="c1"&gt;// If you use Expo you can safely remove this line.&lt;/span&gt;
&lt;span class="nx"&gt;AppRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;StorybookUIRoot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;StorybookUIRoot&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Configure story loader&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last step in setting up &lt;code&gt;react-native-storybook-loader&lt;/code&gt; is configuring in which directory it should look for stories.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;package.json&lt;/code&gt; again and add a config field:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-native-storybook-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"searchDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/components"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"**/*.stories.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outputFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./storybook/storyLoader.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;I wan't it to look inside of the &lt;code&gt;./src/components&lt;/code&gt; directory but you can set it up to look in a different folder, or even add more places it should look in by adding them into the &lt;code&gt;searchDir&lt;/code&gt; array. If you change the other fields you'll need to change your other config to match accordingly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Test component
&lt;/h2&gt;

&lt;p&gt;To test that this part of the setup works lets add a test component and check so everything works. &lt;/p&gt;

&lt;p&gt;I'm making a new directory called &lt;code&gt;src&lt;/code&gt; and inside of the directory I'm adding a folder called &lt;code&gt;components&lt;/code&gt; -&amp;gt; &lt;code&gt;./src/components&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and in these files I'm adding two new files called &lt;code&gt;TestComponent.js&lt;/code&gt; &amp;amp; &lt;code&gt;TestComponent.stories.js&lt;/code&gt; and let's code a test component and add a story for storybook. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/TestComponent.js&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TestComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="nx"&gt;Native&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;TestComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and a story for storybook&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./src/components/TestComponent.stories.js&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;storiesOf&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TestComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./TestComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;storiesOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test Component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TestComponent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Note that while using react native we have to use the &lt;code&gt;storiesOf&lt;/code&gt; api from Storybook. &lt;/p&gt;

&lt;h2&gt;
  
  
  Running everything together
&lt;/h2&gt;

&lt;p&gt;Let's test it out on your device of choice!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn run iOS&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will first run the &lt;code&gt;react-native-storybook-loader&lt;/code&gt; script. It will output a reference to all the files matching the pattern &lt;code&gt;*.stories.js&lt;/code&gt; inside &lt;code&gt;./src/components&lt;/code&gt; to &lt;code&gt;./storybook/storyloader.js&lt;/code&gt; and load them into Storybook. After that it's running storybook as normal. &lt;/p&gt;

&lt;p&gt;Here's what you should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjoecw62ah9dkfoop16zj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjoecw62ah9dkfoop16zj.png" alt="successful-test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully you'll see the test component on the screen. &lt;/p&gt;

&lt;h3&gt;
  
  
  Success!
&lt;/h3&gt;

&lt;p&gt;What did we accomplish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;initiated a new react native project.&lt;/li&gt;
&lt;li&gt;installed &lt;code&gt;@storybook/react-native&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;installed &lt;code&gt;@storybook/react-native-server&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;installed &amp;amp; configured &lt;code&gt;react-native-storybook-loader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Added our first test component and story.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you like this content please bookmark the init post of this series &lt;a href="https://dev.to/ugglr/series-the-ultimate-react-native-ui-library-starter-repo-bho"&gt;here&lt;/a&gt; and stay tuned for part 2!&lt;/p&gt;

&lt;p&gt;You can find the finished repository for the whole series on Github: &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate" rel="noopener noreferrer"&gt;react-native-storybook-boilerplate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consider giving it a star or raising an issue, PRs are most welcome!&lt;/p&gt;

</description>
      <category>react</category>
      <category>tutorial</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Series: The Ultimate React Native UI Library starter repo</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Fri, 24 Jul 2020 11:59:06 +0000</pubDate>
      <link>https://dev.to/ugglr/series-the-ultimate-react-native-ui-library-starter-repo-bho</link>
      <guid>https://dev.to/ugglr/series-the-ultimate-react-native-ui-library-starter-repo-bho</guid>
      <description>&lt;p&gt;If you are developing in React native chances are you are sitting on a personal UI library which you copy &amp;amp; paste between projects. Would it not be great to document, and publish the components online? &lt;/p&gt;

&lt;p&gt;This is the collection post where I'm starting a series. With the goal to setup a repo which can be forked and then makes a very compelling case (in my opinion) for starting development of your own React Native UI library. &lt;/p&gt;

&lt;p&gt;The parts I'm going to be covering:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;setup react native &amp;amp; @storybook/react-native&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-1-setting-up-react-native-with-storybook-36l"&gt;Step 1: Setting up React Native with Storybook&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup react from scratch together with react native web&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-2-setting-up-react-with-react-native-web-30ba"&gt;Step 2: Setting up react with react native web&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setup @storybook/react + react native web to run as a parallel storybook&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/ugglr/step-3-setting-up-storybook-with-react-native-web-show-your-mobile-components-the-browser-12ke"&gt;Step 3: Setting up storybook with react native web: Show your mobile components in a browser&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I've already written out the code so this is a way for me to document how this repo was made, and for others to follow along. &lt;/p&gt;

&lt;p&gt;If you want to jump straight into the code here's the repo &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate/blob/master/README.md"&gt;react-native-storybook-boilerplate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a hosted version of what I'm building: &lt;a href="https://rn-sb-boilerplate.netlify.app/"&gt;hosted site&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Roughly what's going to be done
&lt;/h2&gt;

&lt;p&gt;In a nutshell there's two different setups of Storybook running in parallel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;React Native + Storybook/React-Native&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It was installed following the normal steps of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;doing a fresh &lt;code&gt;npx react-native init&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;running &lt;code&gt;npx -p @storybook/cli sb init&lt;/code&gt; and choosing yes when asked if install @storybook/react-native-server&lt;/li&gt;
&lt;li&gt;installing &amp;amp; configuring &lt;code&gt;react-native-storybook-loader&lt;/code&gt; the project can be found here: &lt;a href="https://github.com/elderfo/react-native-storybook-loader"&gt;react-native-storybook-loader&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;React + Storybook/React&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This installation is less obvious because we have to setup react from scratch, configure babel &amp;amp; webpack, whereas in the &lt;code&gt;webpack.config.js&lt;/code&gt; we need to resolve and apply aliases for our imports, so &lt;code&gt;react-native&lt;/code&gt; becomes &lt;code&gt;react-native-web&lt;/code&gt;. This needs to be done with other packages as well, in this boilerplate I have installed &lt;code&gt;styled-components&lt;/code&gt;, i.e. &lt;code&gt;styled-components/native&lt;/code&gt; imports needs to be switched out to &lt;code&gt;styled-components&lt;/code&gt; when we bundle for the web.&lt;/p&gt;

&lt;p&gt;It was roughly done like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;react-dom&lt;/code&gt;, &lt;code&gt;babel&lt;/code&gt; &amp;amp; &lt;code&gt;webpack&lt;/code&gt; dependencies&lt;/li&gt;
&lt;li&gt;Configuring &lt;code&gt;webpack&lt;/code&gt; to alias &lt;code&gt;react-native&lt;/code&gt; with &lt;code&gt;react-native-web&lt;/code&gt;, and &lt;code&gt;styled-components/native&lt;/code&gt; should resolve to &lt;code&gt;styled-components&lt;/code&gt;. See the full webpack config here: &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate/blob/master/webpack.config.js"&gt;webpack.config.js&lt;/a&gt; also: babel config here: &lt;a href="https://github.com/ugglr/react-native-storybook-boilerplate/blob/master/babel.config.js"&gt;babel.config.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Installing Storybook according to the manual guide in the docs &lt;a href="https://storybook.js.org/docs/guides/guide-react/"&gt;React Storybook Manual Installation Steps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Inside of &lt;code&gt;./.storybook/main.js&lt;/code&gt; configure custom webpack for Storybook, see docs here: &lt;a href="https://storybook.js.org/docs/configurations/custom-webpack-config/"&gt;Storybook custom webpack docs&lt;/a&gt;, from my &lt;code&gt;webpack.config.js&lt;/code&gt; I grab the alias configuration and plug it into Storybook.&lt;/li&gt;
&lt;li&gt;Since Storybook does not support the new syntax of writing stories for React Native I needed to add one more alias where &lt;code&gt;@storybook/react-native&lt;/code&gt; resolves to &lt;code&gt;@storybook/react&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stay tuned for the write-up!
&lt;/h2&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React Native: Getting user device timezone and converting UTC time-stamps using the offset.</title>
      <dc:creator>Carl-W</dc:creator>
      <pubDate>Fri, 19 Jun 2020 12:37:33 +0000</pubDate>
      <link>https://dev.to/ugglr/react-native-getting-user-device-timezone-and-converting-utc-time-stamps-using-the-offset-3jh8</link>
      <guid>https://dev.to/ugglr/react-native-getting-user-device-timezone-and-converting-utc-time-stamps-using-the-offset-3jh8</guid>
      <description>&lt;p&gt;Recently I was tasked to convert all backend generated timestamps from the default UTC to our users device timezone. This is my process of how I encountered some issues along the way and how I solved my ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flowchart
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is the flow I implemented:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get user UTC offset in hours.&lt;/li&gt;
&lt;li&gt;Send backend timestamp &amp;amp; offset into a conversion function that returns the converted+formatted string to the frontend&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The function in step 2 would work like this:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;params:&lt;br&gt;
&lt;code&gt;String: dateString&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Int: offset&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse the date string &lt;code&gt;dateString&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert data into JS Date object.&lt;/li&gt;
&lt;li&gt;Get the current hours of the date object by using JS &lt;code&gt;Date&lt;/code&gt; built-in function &lt;code&gt;getHours()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Set new hours on the Date object by using JS &lt;code&gt;Date&lt;/code&gt; built-in function &lt;code&gt;setHours()&lt;/code&gt;, where we pass in the current hours and add the offset passed into the function.&lt;/li&gt;
&lt;li&gt;Format the string to the frontend&lt;/li&gt;
&lt;li&gt;Return the new converted timestamp&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Let's see that happen in code:&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Building the conversion function
&lt;/h1&gt;

&lt;p&gt;The function would be called like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;convertedTimeStamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatTimeByOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utcStringFromBE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And the function I built based on the steps above looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formatTimeByOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Params:&lt;/span&gt;
  &lt;span class="c1"&gt;// How the backend sends me a timestamp&lt;/span&gt;
  &lt;span class="c1"&gt;// dateString: on the form yyyy-mm-dd hh:mm:ss&lt;/span&gt;
  &lt;span class="c1"&gt;// offset: the amount of hours to add.&lt;/span&gt;

  &lt;span class="c1"&gt;// If we pass anything falsy return empty string&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 1: Parse the backend date string&lt;/span&gt;

  &lt;span class="c1"&gt;// Get Parameters needed to create a new date object&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Step: 2 Make a JS date object with the data&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;month&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;T&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 3: Get the current hours from the object&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentHours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 4: Add the offset to the date object&lt;/span&gt;
  &lt;span class="nx"&gt;dateObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentHours&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 5: stringify the date object, replace the T with a space and slice off the seconds.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newDateString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateObject&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;T&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 6: Return the new formatted date string with the added offset&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;newDateString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/ugglr/Mini-Tutorials-React-Native/blob/master/examples/src/helpers/formatTimeByOffset.js" rel="noopener noreferrer"&gt;GITHUB CODE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tested it out and boom, it works when I pass in random offsets. The time converts properly even when time goes over midnight etc. that is taken care of the JS Date &lt;code&gt;setHours()&lt;/code&gt; method.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Awesome now I just need to get the user offset and we are done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Not quite&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JS Date
&lt;/h2&gt;

&lt;p&gt;My initial thought was that I simply use this method according to the docs here: &lt;a href="https://www.w3schools.com/jsref/jsref_gettimezoneoffset.asp" rel="noopener noreferrer"&gt;JS Date getTimeZone() method&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utcTimeOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTimezoneOffset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;NOTE: Divided by 60 because the method returns the offset in minutes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gave the wrong time&lt;/strong&gt;&lt;br&gt;
However, changing my timezone to the west coast in America (for instance) gave me the wrong converted timestamp by 1 hour!&lt;/p&gt;

&lt;h2&gt;
  
  
  Daylight Savings Time
&lt;/h2&gt;

&lt;p&gt;If we running in a browser this probably would have worked, because the browsers these days will return you a DST adjusted offset (correct me if I'm wrong).&lt;/p&gt;

&lt;p&gt;However, since we are not running in the browser we need to figure out a different way to determine if the user is affected by daylight savings time events. Doing this manually will be tricky because not all countries use DST and when they do, they don't use the same date and time when it goes into power. &lt;strong&gt;So what do we do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's figure out the timezone of the user somehow first, even though we are not running in a browser we are running on a mobile device. There must be a way of getting the time of the device and use that to our advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the mobile device timezone
&lt;/h2&gt;

&lt;p&gt;Every time I want to use a native module in react native, like using the camera, I turn to &lt;a href="https://github.com/react-native-community" rel="noopener noreferrer"&gt;React native community on Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately for us the community has a native module which is called &lt;a href="https://github.com/react-native-community/react-native-localize" rel="noopener noreferrer"&gt;react-native-community/react-native-localize&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I went in and read the docs and found the following method:&lt;br&gt;
&lt;a href="https://github.com/react-native-community/react-native-localize#gettimezone" rel="noopener noreferrer"&gt;getTimeZone()&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;it is described like this:&lt;/p&gt;

&lt;h3&gt;
  
  
  getTimeZone()
&lt;/h3&gt;

&lt;p&gt;Returns the user preferred timezone (based on its device settings, not on its position).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RNLocalize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTimeZone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// -&amp;gt; "Europe/Paris"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Alright, good. I installed the package into my project by doing the usual:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yarn add react-native-localize

cd ios &amp;amp;&amp;amp; pod install

cd ..

yarn run ios


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

&lt;/div&gt;

&lt;p&gt;I ran the example above:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RNLocalize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTimeZone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// -&amp;gt; "Asia/Shanghai"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Ok great if worse comes to worst I can make some kind of lookup table where I keep track of when different timezones go into DST etc. &lt;strong&gt;But there's no need for that, so let's bring in the moment time-zone library&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Moment Timezone
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://momentjs.com/timezone/" rel="noopener noreferrer"&gt;Moment Timezone Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The moment timezone library can take the timezone value generated above and return the UTC offset. Neat!&lt;/p&gt;

&lt;p&gt;Installation:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

yarn add moment-timezone


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

&lt;/div&gt;

&lt;p&gt;Combined with getting the device timezone above we can use it like this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formatTimeByOffset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../helpers/formatTimeByOffset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;RNLocalize&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-localize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;moment&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;moment-timezone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;timeToDisplay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTimeToDisplay&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backEndTimeStamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2001-04-11 10:00:00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// get device timezone eg. -&amp;gt; "Asia/Shanghai"&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deviceTimeZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RNLocalize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTimeZone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Make moment of right now, using the device timezone&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;tz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deviceTimeZone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the UTC offset in hours&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentTimeZoneOffsetInHours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcOffset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Run the function as we coded above.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;convertedToLocalTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatTimeByOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;backEndTimeStamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;currentTimeZoneOffsetInHours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Set the state or whatever&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeToDisplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;convertedToLocalTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Time&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="nx"&gt;into&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;backEndTimeStamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Converted&lt;/span&gt; &lt;span class="nx"&gt;To&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;timeToDisplay&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;deviceTimeZone&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Let's see that in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0pawatsjqkhpekmrfca4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0pawatsjqkhpekmrfca4.png" alt="working example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ugglr/Mini-Tutorials-React-Native/blob/master/examples/src/screens/TimeZoneExample.js" rel="noopener noreferrer"&gt;GITHUB RN CODE EXAMPLE&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Success!
&lt;/h1&gt;

&lt;p&gt;I think there are good ways to make this more compact and stuff, but for a tutorial, I rather go a little bit verbose than miss some detail. &lt;/p&gt;

&lt;p&gt;Let me know if you found this helpful!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
