<?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>Forem: ido evergreen</title>
    <description>The latest articles on Forem by ido evergreen (@idoevergreen).</description>
    <link>https://forem.com/idoevergreen</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%2F196268%2F2db3fca2-5fb7-4cf5-8aa9-50fedd4ebc6c.jpg</url>
      <title>Forem: ido evergreen</title>
      <link>https://forem.com/idoevergreen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/idoevergreen"/>
    <language>en</language>
    <item>
      <title>VELO — I Built a Weekend tool That Doesn't Let You Quit</title>
      <dc:creator>ido evergreen</dc:creator>
      <pubDate>Mon, 02 Mar 2026 00:53:39 +0000</pubDate>
      <link>https://forem.com/idoevergreen/velo-i-built-a-weekend-tool-that-doesnt-let-you-quit-41hp</link>
      <guid>https://forem.com/idoevergreen/velo-i-built-a-weekend-tool-that-doesnt-let-you-quit-41hp</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/weekend-2026-02-28"&gt;DEV Weekend Challenge: Community&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Community
&lt;/h2&gt;

&lt;p&gt;This is for developers who build on weekends.&lt;/p&gt;

&lt;p&gt;You know the feeling: Friday night, you're full of energy. Saturday morning goes great. Sunday afternoon, you're "almost done." Sunday night, the repo gets pushed to GitHub and... that's it. It never gets finished.&lt;/p&gt;

&lt;p&gt;Most of us have a graveyard of these: half-built projects, good ideas, zero shipping.&lt;/p&gt;

&lt;p&gt;The problem isn't time or skill. It's that we're building in private with no real deadline pressure. VELO is my attempt to fix that.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VELO&lt;/strong&gt; is a public project tracker built around one rule: every project has a hard Sunday deadline, and everyone can see your progress.&lt;/p&gt;

&lt;p&gt;You log in with GitHub or Discord, create a project, and start posting updates. If you go quiet for 18 hours, the app starts notifying you. When Sunday hits, the clock stops.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI Idea Generator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The biggest problem for weekend builders isn't time — it's deciding what to build. I built an AI Idea Generator that takes your stack, available hours, and what you're interested in, and gives you a complete, scoped project idea with core features and stretch goals.&lt;/p&gt;

&lt;p&gt;The best part: there's a &lt;strong&gt;[ LAUNCH MISSION ]&lt;/strong&gt; button that instantly creates the project in your account. No copy-paste, no filling out a form. One click from idea to commitment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard Deadlines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every project automatically gets a deadline of the upcoming Sunday at 23:59:59. There's no way to change it. The pressure is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progress Logs with Media&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Updates aren't just text. You can attach screenshots or recordings to each update as proof you're actually building. On the public wall, active projects stand out. Abandoned ones look exactly like what they are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alert System&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go 18 hours without posting an update, and three things fire at the same time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A red alert shows up on your dashboard&lt;/li&gt;
&lt;li&gt;A push notification hits your desktop (if you enabled it)&lt;/li&gt;
&lt;li&gt;An email drops in your inbox&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's annoying by design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sound Feedback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every click, update, and alert has a sound. Not from audio files — I synthesized everything with the Web Audio API using oscillators and filters. It makes the app feel heavy. Like what you're doing matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public Wall&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every project is visible to anyone. Other developers can boost your project with a cheer. Building in the open adds stakes you can't manufacture on your own.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;[&lt;a href="https://velo.idoevergreen.me" rel="noopener noreferrer"&gt;https://velo.idoevergreen.me&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://youtu.be/McI0maAPgtE?si=eyxD22tkRspUxFkm" rel="noopener noreferrer"&gt;https://youtu.be/McI0maAPgtE?si=eyxD22tkRspUxFkm&lt;/a&gt;]&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15&lt;/strong&gt; — App Router with Server Actions for all data writes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase&lt;/strong&gt; — Postgres database, GitHub + Discord auth, media storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI (gpt-4o-mini)&lt;/strong&gt; — Powers the AI Idea Generator via Vercel AI SDK&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resend&lt;/strong&gt; — Sends a welcome email when you first sign up, plus alert emails for stale projects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Audio API&lt;/strong&gt; — All sound effects synthesized in the browser, no audio files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Worker&lt;/strong&gt; — Desktop push notifications even when the tab is closed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry&lt;/strong&gt; — Error tracking&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;I kept starting projects I never finished. I'd have a great Saturday session, get distracted Sunday afternoon, and never ship.&lt;/p&gt;

&lt;p&gt;VELO is the app I wish existed when I was staring at yet another abandoned repo. It's not kind about deadlines. It doesn't tell you it's okay to miss. It just shows you the clock and lets the community watch.&lt;/p&gt;

&lt;p&gt;That's the accountability I needed.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Routing in Expo: Expo Router</title>
      <dc:creator>ido evergreen</dc:creator>
      <pubDate>Mon, 03 Apr 2023 03:30:39 +0000</pubDate>
      <link>https://forem.com/idoevergreen/routing-in-expo-expo-router-5a6e</link>
      <guid>https://forem.com/idoevergreen/routing-in-expo-expo-router-5a6e</guid>
      <description>&lt;p&gt;Expo is a platform that enables building native iOS and Android apps using React Native, while Expo Router is a file-based router designed for universal React Native apps that can be utilized to incorporate navigation into your application. it makes every file in our &lt;code&gt;app&lt;/code&gt; directory a route. In this article, we will explore how to use Expo router by building a &lt;a href="https://en.wikipedia.org/wiki/Rick_and_Morty" rel="noopener noreferrer"&gt;Rick and Morty&lt;/a&gt; app that consumes a &lt;a href="https://rickandmortyapi.com/documentation" rel="noopener noreferrer"&gt;REST API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;get code on Github: &lt;a href="https://github.com/evergreenx/ricknmorty-expo-router" rel="noopener noreferrer"&gt;https://github.com/evergreenx/ricknmorty-expo-router&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a preview of what we will be building&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%2F19bowftb3b02qrjw82dj.gif" 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%2F19bowftb3b02qrjw82dj.gif" width="600" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we dive into the building, there are a few prerequisites you should be familiar with :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Node js v14+.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Basic knowledge of react native&lt;/strong&gt; : Expo is built on react native, so you should have some understanding of the core concepts of React Native.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Familiarity with JavaScript&lt;/strong&gt; : Our application will be built using JavaScript, so you should have a basic understanding of the language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understanding of REST API&lt;/strong&gt; : you should have a basic understanding to consume a REST API.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are new to any of these concepts, I recommend taking some time to learn them before continuing with this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Expo Router?
&lt;/h2&gt;

&lt;p&gt;It is a routing concept built on top of &lt;a href="https://reactnavigation.org/" rel="noopener noreferrer"&gt;React Navigation suite&lt;/a&gt;. if you are familiar with how Nextjs handles navigation that should give you a basic understanding of Expo router. that is every file in your &lt;code&gt;app&lt;/code&gt; directory becomes a route in your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Get Started
&lt;/h2&gt;

&lt;p&gt;To get started, head over to &lt;a href="https://expo.github.io/router/docs/" rel="noopener noreferrer"&gt;expo documentation&lt;/a&gt; to install Expo cli and Expo Go, if you already don't have it installed. Now you need to create a new expo project with Expo CLI. You can use the following command to create a new expo typescript project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-native-app -t with-typescript ricknmorty-expo-router

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

&lt;/div&gt;



&lt;p&gt;Once, it is done installing our project, navigate to the project directory and start the development server by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ricknmorty-expo-router
npx expo start

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

&lt;/div&gt;



&lt;p&gt;This will launch the Expo development server, which you can preview your app in the browser or on your phone using &lt;a href="https://docs.expo.dev/get-started/installation/#expo-go-app-for-android-and-ios" rel="noopener noreferrer"&gt;Expo Go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If all went well you should have a screen preview 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%2Fs1e3bahlhyub21xadokf.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%2Fs1e3bahlhyub21xadokf.png" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Install Expo Router
&lt;/h3&gt;

&lt;p&gt;Now let's install expo router and its peer dependencies :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar

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

&lt;/div&gt;



&lt;p&gt;After successful installation, let's configure our app to use expo router.&lt;/p&gt;

&lt;p&gt;Create a new file &lt;code&gt;index.ts&lt;/code&gt; in the root of your project. If it exists already, replace it with the following code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "expo-router/entry";

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

&lt;/div&gt;



&lt;p&gt;Also, create &lt;code&gt;app.json&lt;/code&gt; file and add this code, we are adding a deep linking scheme to our app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "expo": {
    "scheme": "myapp",

    "web": {
      "bundler": "metro"
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;Update your &lt;code&gt;package.json&lt;/code&gt; with this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// If you use Yarn
"resolutions": {
    "metro": "0.76.0",
    "metro-resolver": "0.76.0"
  }

// if you use npm 
"overrides": {
    "metro": "0.76.0",
    "metro-resolver": "0.76.0"
  }

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

&lt;/div&gt;



&lt;p&gt;Next, we have to update our &lt;code&gt;babel.config.js&lt;/code&gt; file and replace the content with the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: [require.resolve("expo-router/babel")],
  };
};

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

&lt;/div&gt;



&lt;p&gt;Let us create a new directory called &lt;code&gt;app&lt;/code&gt; , this is where our routes will live, go ahead and add a new &lt;code&gt;index.tsx&lt;/code&gt; file in your just-created directory. your project should look something 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%2Fk40ghpdgisxm5vr2admg.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%2Fk40ghpdgisxm5vr2admg.png" width="200" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this add a react function component to &lt;code&gt;index.tsx&lt;/code&gt; and delete &lt;code&gt;App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { View, Image, ViewStyle } from "react-native";
import React from "react";

const Index = () =&amp;gt; {
  return (
    &amp;lt;View style={$ViewStyle}&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default Index;

const $ViewStyle: ViewStyle = {
  flex: 1,
  padding: 20,
  backgroundColor: "#FFDEAD",
};

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

&lt;/div&gt;



&lt;p&gt;Now restart your server.&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;






&lt;p&gt;Here is a preview of how our app looks&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%2Fd7wd8265j13zkzqpqj4h.jpeg" 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%2Fd7wd8265j13zkzqpqj4h.jpeg" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetch Data
&lt;/h3&gt;

&lt;p&gt;We have successfully set up our project with Expo Router and &lt;code&gt;index.js&lt;/code&gt; now serves as our home screen. Next, we are going to consume the &lt;a href="https://rickandmortyapi.com/documentation" rel="noopener noreferrer"&gt;rick and morty&lt;/a&gt; API. For this article, we will be using only the character's resources. To consume the API we are going to make use of &lt;a href="https://github.com/infinitered/apisauce" rel="noopener noreferrer"&gt;&lt;strong&gt;Apisauce&lt;/strong&gt;&lt;/a&gt; which is an HTTP client wrapper built on Axios. Let's install the package.&lt;br&gt;
&lt;/p&gt;

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

// yarn
yarn add apisauce

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

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;interface.ts&lt;/code&gt; file in the root of our application, this is where the &lt;a href="https://www.typescriptlang.org/docs/handbook/interfaces.html" rel="noopener noreferrer"&gt;interface&lt;/a&gt; for our Characters API response will live.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// interface.ts

  export interface Location {
    name: string;
    url: string;
  }

export interface Character {
    id: number;
    name: string;
    status: string;
    species: string;
    type: string;
    gender: string;
    origin: Location;
    location: Location;
    image: string;
    medium : string;
    episode: string[];
    url: string;
    created: string;
  }

  export interface ApiResponse {
    info: {
      count: number;
      pages: number;
      next: string;
      prev: string;
    };
    results: Character[];
  }

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

&lt;/div&gt;



&lt;p&gt;Moving forward create a new file called &lt;code&gt;api.ts&lt;/code&gt; and copy this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { create } from "apisauce";
import { ApiResponse} from "./interface";
const api = create({
  baseURL: "https://rickandmortyapi.com/api/",
  headers: { Accept: "application/json" },
});

export const getCharacters = async (): Promise&amp;lt;ApiResponse&amp;gt; =&amp;gt; {
  const response = await api.get("/character");
  return response.data as ApiResponse;
};

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

&lt;/div&gt;



&lt;p&gt;Firstly we are importing &lt;code&gt;create&lt;/code&gt; from apisauce and also importing the interface we created earlier. Next, we are defining the API with the &lt;code&gt;create&lt;/code&gt; method. The &lt;code&gt;getCharacters&lt;/code&gt; function is an async function that makes a GET request to the &lt;code&gt;/characters&lt;/code&gt; endpoint. Open and replace the &lt;code&gt;index.tsx&lt;/code&gt; component with the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { View, Image, ViewStyle, Text, TextStyle } from "react-native";
import React, { useEffect, useState } from "react";
import { getCharacters } from "../api";
import { Character } from "../interface";
import CharacterCard from "../component/CharacterCard";

const Index = () =&amp;gt; {
  const [characters, setCharacters] = useState&amp;lt;Character[]&amp;gt;([]);
  const [loading, setLoading] = useState&amp;lt;boolean&amp;gt;(true);
  const [error, setError] = useState&amp;lt;string&amp;gt;("");

  useEffect(() =&amp;gt; {
    setLoading(true);
    const fetchCharactersData = async () =&amp;gt; {
      try {
        const res = await getCharacters();
        setCharacters(res.results);
      } catch (err) {
        setLoading(false);
        setCharacters([]);
        setError("An error occurred");
      } finally {
        setLoading(false);
      }
    };
    fetchCharactersData();
  }, []);
  console.log(characters);

  return (
    &amp;lt;View style={$container}&amp;gt;
      &amp;lt;View&amp;gt;
        &amp;lt;Image
          source={{
            uri: "https://res.cloudinary.com/evergreenx/image/upload/v1680259111/Logo_1_tdttqu.png",
          }}
          resizeMode="contain"
          alt="logo"
          style={{ width: 300, height: 200, alignSelf: "center" }}
        /&amp;gt;
      &amp;lt;/View&amp;gt;

      {loading &amp;amp;&amp;amp; (
        &amp;lt;Image
          source={{
            uri: "https://res.cloudinary.com/evergreenx/image/upload/v1680297056/Loading_component_tr2ec6.png",
          }}
          resizeMode="contain"
          style={{ width: 300, height: 200, alignSelf: "center" }}
        /&amp;gt;
      )}
      {error &amp;amp;&amp;amp; &amp;lt;Text style={$errorText}&amp;gt;{error}&amp;lt;/Text&amp;gt;}
      {characters &amp;amp;&amp;amp; &amp;lt;CharacterCard characters={characters} /&amp;gt;}
    &amp;lt;/View&amp;gt;
  );
};

export default Index;

const $container: ViewStyle = {
  flex: 1,
  width: "100%",
  backgroundColor: "#FFDEAD",
};

const $errorText: TextStyle = {
  color: "red",
  fontSize: 20,
  alignSelf: "center",
};

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

&lt;/div&gt;



&lt;p&gt;We imported our async function and used a useEffect to get our data on-load of the component, The error and data have been saved in a useState. We are also importing &lt;code&gt;CharacterCard&lt;/code&gt; component which does not exist yet ,it will be used to display the data.&lt;/p&gt;




&lt;h3&gt;
  
  
  Show Characters
&lt;/h3&gt;

&lt;p&gt;Now let's show the data, create a component folder at the root of the project, and add a new file called &lt;code&gt;CharacterCard.tsx&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  View,
  Text,
  FlatList,
  TextStyle,
  ViewStyle,
  Image,
} from "react-native";
import React from "react";
import { Character } from "../interface";
type CharacterCardProps = {
  characters: Character[];
};

export default function characterCard({ characters }: CharacterCardProps) {
  const renderCharacters = ({ item }: { item: Character }) =&amp;gt; {
    return (
      &amp;lt;View style={$characterContainer}&amp;gt;
        &amp;lt;View style={$characterImageContainer}&amp;gt;
          &amp;lt;Image
            source={{ uri: item?.image }}
            style={{
              width: "100%",
              height: 150,
              borderBottomLeftRadius: 0,
              borderBottomRightRadius: 0,
              borderRadius: 10,
            }}
            resizeMode="cover"
          /&amp;gt;
        &amp;lt;/View&amp;gt;

        &amp;lt;View style={$characterInfoContainer}&amp;gt;
          &amp;lt;Text style={$characterText}&amp;gt;{item?.name}&amp;lt;/Text&amp;gt;
          &amp;lt;Text style={$characterSpecies}&amp;gt;{item?.species}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  };

const renderHeader = () =&amp;gt; {
    return (
      &amp;lt;View&amp;gt;
        &amp;lt;Image
          source={{
            uri: "https://res.cloudinary.com/evergreenx/image/upload/v1680259111/Logo_1_tdttqu.png",
          }}
          style={{ width: 300, height: 200, alignSelf: "center" }}
          resizeMode="contain"
          alt="logo"
        /&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  };

  return (
    &amp;lt;View style={$container}&amp;gt;
      &amp;lt;FlatList
        style={{ width: "100%", padding: 10 }}
        data={characters}
        renderItem={renderCharacters}
        keyExtractor={(item) =&amp;gt; item.id.toString()}
        showsHorizontalScrollIndicator={true}
        numColumns={2}
        ListHeaderComponent={renderHeader}
      /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const $container: ViewStyle = {
  flex: 1,
  alignItems: "center",
  justifyContent: "center",
};

const $characterContainer: ViewStyle = {
  backgroundColor: "#fff",
  height: 230,
  width: "45%",
  borderRadius: 10,
  marginVertical: 10,
  marginHorizontal: 10,
};
const $characterImageContainer: ViewStyle = {
  width: "100%",
  overflow: "hidden",
  marginBottom: 10,
};

const $characterText: TextStyle = {
  color: "#000",
  fontSize: 18,
  fontWeight: "500",
};

const $characterSpecies: TextStyle = {
  color: "#000",
  fontSize: 13,
  fontWeight: "500",
  marginTop: 5,
};

const $characterInfoContainer: ViewStyle = {
  padding: 10,
};

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

&lt;/div&gt;



&lt;p&gt;Let's break down what the code does, so we render a grid of cards containing each character, also the component takes a prop &lt;code&gt;characters&lt;/code&gt; which is an array of objects. The component uses a &lt;code&gt;FlatList&lt;/code&gt; to render the cards and the &lt;code&gt;keyExtractor&lt;/code&gt; prop is used to extract a unique key for each item in the array, &lt;code&gt;numcolumns&lt;/code&gt; prop is set to display the cards in a grid with two columns and the &lt;code&gt;showsVerticalScrollIndicator&lt;/code&gt; prop is set to &lt;code&gt;false&lt;/code&gt; to hide the vertical scroll indicator. &lt;code&gt;renderHeader&lt;/code&gt; prop is used to render a component on top of the list, we render an image component with an our image source hosted on Cloudinary.&lt;/p&gt;

&lt;p&gt;We define &lt;code&gt;renderCharacters&lt;/code&gt; a function that takes an object with an item property that represents a single character from the &lt;code&gt;characters&lt;/code&gt; array. The function returns a JSX representation of a character card and lastly, and we define some styles to make the cards look good.&lt;/p&gt;

&lt;p&gt;So far our app is coming together piece by piece. 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%2F3of87wfsoyv1pivt69to.jpeg" 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%2F3of87wfsoyv1pivt69to.jpeg" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Move Between Screens
&lt;/h3&gt;

&lt;p&gt;One should be able to move between screens and we will see how to do that in Expo Router. To achieve this expo router has a &lt;a href="https://expo.github.io/router/docs/features/linking" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Link&lt;/code&gt;&lt;/a&gt;&lt;code&gt;/&amp;gt;&lt;/code&gt; component or &lt;code&gt;useRouter&lt;/code&gt; hook. so let's make it when we click on a character we move to a dynamic route to view that particular character's details.&lt;/p&gt;

&lt;p&gt;Head over to the project and create a new folder inside the &lt;code&gt;app&lt;/code&gt; directory and name it &lt;code&gt;details&lt;/code&gt; , then create a file &lt;code&gt;[id].tsx&lt;/code&gt; inside this folder. This will serve as our dynamic route screen, where characters' details will be shown. Expo router makes it easy to add navigation on the fly. Add the code to our just created screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { View, Text, ViewStyle, TextStyle, Image } from "react-native";
import React, { useEffect, useState } from "react";
import { Link, Stack } from "expo-router";
import { useSearchParams } from "expo-router";
import { getCharacter } from "../../api";

const Details = () =&amp;gt; {
  const [character, setCharacter] = useState&amp;lt;any&amp;gt;(null);
  const [loading, setLoading] = useState&amp;lt;boolean&amp;gt;(true);
  const [error, setError] = useState&amp;lt;string&amp;gt;("");
  const { id } = useSearchParams();

  useEffect(() =&amp;gt; {
    const fetchCharactersData = async () =&amp;gt; {
      try {
        const res = await getCharacter(id);
        setCharacter(res);
      } catch (err) {
        setLoading(false);
        setCharacter([]);
        setError("An error occurred");
      } finally {
        setLoading(false);
      }
    };
    fetchCharactersData();
  }, []);

  return (
    &amp;lt;View style={$container}&amp;gt;
      {error &amp;amp;&amp;amp; &amp;lt;Text style={$errorText}&amp;gt;{error}&amp;lt;/Text&amp;gt;}

      {loading &amp;amp;&amp;amp; (
        &amp;lt;Image
          source={{
            uri: "https://res.cloudinary.com/evergreenx/image/upload/v1680297056/Loading_component_tr2ec6.png",
          }}
          resizeMode="contain"
          style={{
            width: 300,
            height: 200,
            alignSelf: "center",
            marginTop: 100,
          }}
        /&amp;gt;
      )}
      {character &amp;amp;&amp;amp; (
        &amp;lt;&amp;gt;
          &amp;lt;Link
            href={{
              pathname: "/",
            }}
            style={$backButton}
          &amp;gt;
            &amp;lt;Text style={$backButtonText}&amp;gt;Back&amp;lt;/Text&amp;gt;
          &amp;lt;/Link&amp;gt;

          &amp;lt;View style={$characterImageContainer}&amp;gt;
            &amp;lt;Image
              source={{ uri: character?.image }}
              style={{
                width: 250,
                height: 250,
                borderRadius: 150,
              }}
              resizeMode="contain"
            /&amp;gt;
            &amp;lt;Text style={$characterName}&amp;gt;{character?.name}&amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View style={$characterInfoContainer}&amp;gt;
            &amp;lt;View style={$characterInfo}&amp;gt;
              &amp;lt;Text style={$characterText}&amp;gt;Gender: &amp;lt;/Text&amp;gt;
              &amp;lt;Text style={$characterTextInfo}&amp;gt;{character?.gender}&amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;

            &amp;lt;View style={$characterInfo}&amp;gt;
              &amp;lt;Text style={$characterText}&amp;gt;Status: &amp;lt;/Text&amp;gt;
              &amp;lt;Text style={$characterTextInfo}&amp;gt;{character?.status}&amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;

            &amp;lt;View style={$characterInfo}&amp;gt;
              &amp;lt;Text style={$characterText}&amp;gt;Species: &amp;lt;/Text&amp;gt;
              &amp;lt;Text style={$characterTextInfo}&amp;gt;{character?.species}&amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;

            &amp;lt;View style={$characterInfo}&amp;gt;
              &amp;lt;Text style={$characterText}&amp;gt;origin: &amp;lt;/Text&amp;gt;
              &amp;lt;Text style={$characterTextInfo}&amp;gt;{character?.origin.name}&amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;

            &amp;lt;View style={$characterInfo}&amp;gt;
              &amp;lt;Text style={$characterText}&amp;gt;location: &amp;lt;/Text&amp;gt;
              &amp;lt;Text style={$characterTextInfo}&amp;gt;{character?.location.name}&amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;
          &amp;lt;/View&amp;gt;
        &amp;lt;/&amp;gt;
      )}
    &amp;lt;/View&amp;gt;
  );
};

export default Details;

const $container: ViewStyle = {
  flex: 1,
  width: "100%",
  backgroundColor: "#FFDEAD",

  paddingVertical: 40,
  paddingHorizontal: 20,
};

const $characterImageContainer: ViewStyle = {
  width: "100%",
  padding: 15,
  borderRadius: 10,
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
};

const $characterName: TextStyle = {
  color: "#081F32",
  marginVertical: 16,
  fontSize: 30,
  fontWeight: "400",
};

const $characterInfoContainer: ViewStyle = {
  width: "100%",
  padding: 15,
  borderRadius: 10,
};

const $characterText: TextStyle = {
  color: "#081F32",
  marginVertical: 3,
  fontSize: 16,
  fontWeight: "700",
  textTransform: "capitalize",
  display: "flex",
  flexDirection: "row",
};

const $characterTextInfo: TextStyle = {
  color: "#6E798C",
  fontSize: 14,
  fontWeight: "400",
};

const $characterInfo: ViewStyle = {
  padding: 5,
  marginVertical: 3,
  borderBottomColor: "#979797",
  borderBottomWidth: 0.5,
};

const $backButton: ViewStyle = {
  width: 100,
  height: 40,
  borderRadius: 10,
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
  marginBottom: 20,
  marginTop: 10,
};

const $backButtonText: TextStyle = {
  color: "#979797",
  fontSize: 16,
  fontWeight: "700",
};

const $errorText: TextStyle = {
  color: "red",
  fontSize: 16,
  fontWeight: "700",
  alignSelf: "center",
  paddingTop: 100,
};

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

&lt;/div&gt;



&lt;p&gt;In the code above we import Link and useSearchParams for expo router. We will be using Link to a back button and useSearchParams to return the URL search parameters. we imported the async function &lt;code&gt;getCharacter&lt;/code&gt; which is yet to be created.&lt;/p&gt;

&lt;p&gt;A useEffect to fetch our data for a single character by the &lt;code&gt;id&lt;/code&gt; . Check API documentation here. We are setting some states for our data. lastly, we are returning JSX based on our data. for the &lt;code&gt;Link&lt;/code&gt; component from expo router, it takes a &lt;code&gt;href&lt;/code&gt; prop. and this takes an object with a pathname that &lt;code&gt;/&lt;/code&gt; represents our home screen. we could also define this way &lt;code&gt;&amp;lt;Link href="/" &amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let's update our &lt;code&gt;api&lt;/code&gt; file with the &lt;code&gt;getCharacter&lt;/code&gt; function. replace your code with this below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { create } from "apisauce";
import { ApiResponse, Character } from "./interface";
const api = create({
  baseURL: "https://rickandmortyapi.com/api/",
  headers: { Accept: "application/json" },
});

export const getCharacters = async (): Promise&amp;lt;ApiResponse&amp;gt; =&amp;gt; {
  const response = await api.get("/character");
  if (!response.ok) throw new Error(response.problem);
  return response.data as ApiResponse;
};

export const getCharacter = async (id: string): Promise&amp;lt;Character&amp;gt; =&amp;gt; {
  const response = await api.get(`/character/${id}`);
  if (!response.ok) throw new Error(response.problem);
  return response.data as Character;
};

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

&lt;/div&gt;



&lt;p&gt;We added a new async function &lt;code&gt;getCharacter&lt;/code&gt; to fetch a single character based on the &lt;code&gt;id&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Let update &lt;code&gt;CharacterCard.tsx&lt;/code&gt; so when we click on a card we will be taken to a new screen with details containing that particular character.&lt;/p&gt;

&lt;p&gt;Update the component with the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  View,
  Text,
  FlatList,
  TextStyle,
  ViewStyle,
  Image,
  Pressable,
} from "react-native";
import React from "react";
import { Character } from "../interface";

import { useRouter } from "expo-router";
type CharacterCardProps = {
  characters: Character[];
};

export default function characterCard({ characters }: CharacterCardProps) {
  const router = useRouter();
  const renderCharacters = ({ item }: { item: Character }) =&amp;gt; {
    return (
      &amp;lt;Pressable
        style={$characterContainer}
        onPress={() =&amp;gt; {
          router.push({
            pathname: "details/id/",
            params: { id: item?.id },
          });
        }}
      &amp;gt;
        &amp;lt;View style={$characterImageContainer}&amp;gt;
          &amp;lt;Image
            source={{ uri: item?.image }}
            style={{
              width: "100%",
              height: 150,
              borderBottomLeftRadius: 0,
              borderBottomRightRadius: 0,
              borderRadius: 10,
            }}
          /&amp;gt;
        &amp;lt;/View&amp;gt;

        &amp;lt;View style={$characterInfoContainer}&amp;gt;
          &amp;lt;Text style={$characterText}&amp;gt;{item?.name}&amp;lt;/Text&amp;gt;
          &amp;lt;Text style={$characterSpecies}&amp;gt;{item?.species}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/Pressable&amp;gt;
    );
  };

  const renderHeader = () =&amp;gt; {
    return (
      &amp;lt;View&amp;gt;
        &amp;lt;Image
          source={{
            uri: "https://res.cloudinary.com/evergreenx/image/upload/v1680259111/Logo_1_tdttqu.png",
          }}
          style={{ width: 300, height: 200, alignSelf: "center" }}
          resizeMode="contain"
          alt="logo"
        /&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  };

  return (
    &amp;lt;View style={$container}&amp;gt;
      &amp;lt;FlatList
        style={{ width: "100%", padding: 10, marginBottom: 20 }}
        data={characters}
        renderItem={renderCharacters}
        keyExtractor={(item) =&amp;gt; item.id.toString()}
        showsVerticalScrollIndicator={false}
        numColumns={2}
        ListHeaderComponent={renderHeader}
      /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const $container: ViewStyle = {
  flex: 1,
  alignItems: "center",
  justifyContent: "center",
};

const $characterContainer: ViewStyle = {
  backgroundColor: "#fff",
  height: 230,
  width: "45%",
  borderRadius: 10,
  marginVertical: 10,
  marginHorizontal: 10,
};
const $characterImageContainer: ViewStyle = {
  width: "100%",
  overflow: "hidden",
  marginBottom: 10,
};

const $characterText: TextStyle = {
  color: "#000",
  fontSize: 18,
  fontWeight: "500",
};

const $characterSpecies: TextStyle = {
  color: "#000",
  fontSize: 13,
  fontWeight: "500",
  marginTop: 5,
};

const $characterInfoContainer: ViewStyle = {
  padding: 10,
};

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

&lt;/div&gt;



&lt;p&gt;The new changes contained in the code above, we imported &lt;code&gt;useRouter&lt;/code&gt; hook from expo router, and we will use it to navigate to the dynamic screen we created earlier. as stated in the docs we could use the Link component to move between and we can also use the useRouter hook to navigate imperatively.&lt;/p&gt;

&lt;p&gt;On our card, we added a &lt;code&gt;Pressable&lt;/code&gt; component, onPress of the card we will be taken to the &lt;code&gt;details/id&lt;/code&gt; and we are passing a param to the screen which is &lt;code&gt;id&lt;/code&gt; representing a single character. Then use the &lt;code&gt;id&lt;/code&gt; to get data from our API for that particular character.&lt;/p&gt;

&lt;p&gt;When we click on a card, we should get a screen like this containing details of the character you clicked on.&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%2F2ae8s1m8olor1opnoova.jpeg" 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%2F2ae8s1m8olor1opnoova.jpeg" width="800" height="1777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the article, we have explored how to use the Expo Router to add navigation to our app and also how we could fetch data from an API using apisauce.&lt;/p&gt;

&lt;p&gt;This is a little of what we could do with Expo Router, check out the docs to learn more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://expo.github.io/router/docs/guides/" rel="noopener noreferrer"&gt;https://expo.github.io/router/docs/guides/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://expo.github.io/router/docs/guides/tabs" rel="noopener noreferrer"&gt;https://expo.github.io/router/docs/guides/tabs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://expo.github.io/router/docs/guides/headers" rel="noopener noreferrer"&gt;https://expo.github.io/router/docs/guides/headers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://expo.github.io/router/docs/guides/auth" rel="noopener noreferrer"&gt;https://expo.github.io/router/docs/guides/auth&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Credits&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://expo.github.io/router/docs" rel="noopener noreferrer"&gt;https://expo.github.io/router/docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.expo.dev/" rel="noopener noreferrer"&gt;https://docs.expo.dev/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/infinitered/apisauce" rel="noopener noreferrer"&gt;https://github.com/infinitered/apisauce&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://rickandmortyapi.com/documentation/" rel="noopener noreferrer"&gt;https://rickandmortyapi.com/documentation/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Steps to upgrade your project to React 18</title>
      <dc:creator>ido evergreen</dc:creator>
      <pubDate>Fri, 08 Apr 2022 08:46:15 +0000</pubDate>
      <link>https://forem.com/idoevergreen/steps-to-upgrade-your-project-to-react-18-1jih</link>
      <guid>https://forem.com/idoevergreen/steps-to-upgrade-your-project-to-react-18-1jih</guid>
      <description>&lt;p&gt;React 18 is the next major release of React that was expected to be released in 2019. There are many new features and improvements in this version of React, including a brand new experimental API called Suspense that will make it easier to build interactive and high-performance web applications.&lt;/p&gt;

&lt;p&gt;It is important to know that there are no breaking changes in this version of React and you can upgrade to React 18 without any problems. The only thing you need to do when upgrading from React 18 is to update your package dependencies. So we will be upgrading an existing react application to react 18.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Node 14+ or higher installed on your local machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;any text editor of choice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get your APP_ID and API_KEY from &lt;a href="https://developer.edamam.com/edamam-recipe-api" rel="noopener noreferrer"&gt;Edaman api&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Let's get started
&lt;/h1&gt;

&lt;p&gt;This is the GitHub repo containing our react project. &lt;a href="https://github.com/evergreenx/Recipe-Search" rel="noopener noreferrer"&gt;https://github.com/evergreenx/Recipe-Search&lt;/a&gt; you could clone the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:evergreenx/Recipe-Search.git

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

&lt;/div&gt;



&lt;p&gt;after cloning the project, create a .env file and add your API key gotten from &lt;a href="https://www.edamam.com/" rel="noopener noreferrer"&gt;Edaman&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REACT_APP_API_ID = 'your API ID'
REACT_APP_API_KEY= 'your API key'

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

&lt;/div&gt;



&lt;p&gt;then open the project directory in your IDE of choice run the command to install the project dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
or 
yarn install

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

&lt;/div&gt;



&lt;p&gt;after installing the node modules&lt;/p&gt;

&lt;p&gt;run the project&lt;br&gt;
&lt;/p&gt;

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

or

yarn start

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

&lt;/div&gt;



&lt;p&gt;you should see a page 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%2Fzyizmgo6fbrqje8j4ji8.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%2Fzyizmgo6fbrqje8j4ji8.png" alt="recipe-search-55dd2a.netlify.app_.png" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if you check the package.json file this project was created with react 17.0.1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"dependencies": {
    "@testing-library/jest-dom": "^5.11.6",
    "@testing-library/react": "^11.2.2",
    "@testing-library/user-event": "^12.2.2",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "web-vitals": "^0.2.4"
  },

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

&lt;/div&gt;



&lt;p&gt;we are going to update the project to react 18.&lt;/p&gt;

&lt;p&gt;first off run the command to install the latest version of react and react-dom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install react@latest react-dom@latest

or

yarn add react@latest react-dom@latest

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

&lt;/div&gt;



&lt;p&gt;if everything works out fine you should get updated dependencies looking like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "dependencies": {
    "@testing-library/jest-dom": "^5.11.6",
    "@testing-library/react": "^11.2.2",
    "@testing-library/user-event": "^12.2.2",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "react-scripts": "4.0.1",
    "web-vitals": "^0.2.4"
  },

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

&lt;/div&gt;



&lt;p&gt;Hurray 🥳 🥳 🥳 . We just updated the react version to the latest. Now we aren't finally done. if you check your console you should get this 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%2Foslo6pjodsmv7rhc04sk.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%2Foslo6pjodsmv7rhc04sk.png" alt="error.png" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So basically react 18 introduces a new root API that makes managing roots easier.&lt;/p&gt;

&lt;p&gt;open the index.js file, import the new root API&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createRoot } from 'react-dom/client';

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

&lt;/div&gt;



&lt;p&gt;replace this part of the &lt;code&gt;index.js&lt;/code&gt; too&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Before
ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);

// After
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;{" "}
  &amp;lt;/React.StrictMode&amp;gt;
);

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We were able to upgrade the project to react 18 without issues, so you could use the same steps to upgrade other projects.&lt;/p&gt;

&lt;p&gt;You could check out the full blog about &lt;a href="https://reactjs.org/blog/2022/03/29/react-v18.html" rel="noopener noreferrer"&gt;react 18&lt;/a&gt; release to learn more.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
