<?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: Sveta Slepner</title>
    <description>The latest articles on DEV Community by Sveta Slepner (@svetaslepner).</description>
    <link>https://dev.to/svetaslepner</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%2F1017551%2F3b59e9dd-28dd-415d-a4f0-3d1cdd33462e.jpg</url>
      <title>DEV Community: Sveta Slepner</title>
      <link>https://dev.to/svetaslepner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/svetaslepner"/>
    <language>en</language>
    <item>
      <title>GitHub Actions - A Beginner's Guide to Automating Your Development Process</title>
      <dc:creator>Sveta Slepner</dc:creator>
      <pubDate>Mon, 06 Feb 2023 16:25:36 +0000</pubDate>
      <link>https://dev.to/svetaslepner/github-actions-a-beginners-guide-to-automating-your-development-process-17gd</link>
      <guid>https://dev.to/svetaslepner/github-actions-a-beginners-guide-to-automating-your-development-process-17gd</guid>
      <description>&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%2F9yntoaz1dyvvq4moqw8f.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%2F9yntoaz1dyvvq4moqw8f.jpg" alt="chemex" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a front-end developer, I was never really drawn to the "DevOps" side of my day-to-day work. The major reason is that up until now, in all of the places I have worked in, we've been using Jenkins. And while it's a powerful tool no doubt, it sure is unwelcoming and hard to get started with. &lt;/p&gt;

&lt;p&gt;But in recent years GitHub has stepped into the game and in 2018 released "GitHub Actions", a platform for creating custom, automated development workflows directly within the GitHub ecosystem.&lt;/p&gt;

&lt;p&gt;Whether you want to create a CI/CD pipeline or automate GitHub-related flows like opening a PR, adding automated comments, or sending a Slack notification each time someone merges a commit to master, GitHub Actions can help you create these processes and save you time and effort. And the best part is &lt;strong&gt;how straightforward it is&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;In this guide, we'll cover the basics of GitHub Actions and show you how to get started with them. We'll go through the process of setting up a simple workflow and explain some of the key concepts you need to know. By the end, you'll be able to use GitHub Actions to automate your own workflow and take your productivity to the next level!&lt;/p&gt;

&lt;h2&gt;
  
  
  First, some GitHub Actions terminology
&lt;/h2&gt;

&lt;p&gt;Well, the name might be GitHub Actions, but let's put that aside for one second. What we're actually running are workflows. A workflow is a collection of jobs that are triggered by an event.&lt;/p&gt;

&lt;p&gt;Here's an example of a simple workflow's structure:&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%2F8vf2cag4hlibwturgzw3.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%2F8vf2cag4hlibwturgzw3.jpg" alt="A github actions workflow" width="691" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, this workflow is running two jobs. A &lt;strong&gt;job&lt;/strong&gt; is a set of steps that are executed in sequence. Each step of a job can be an action. An &lt;strong&gt;action&lt;/strong&gt; is an individual step within a job that can perform a variety of tasks such as running a script, building an application, deploying code, or running tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a workflow
&lt;/h2&gt;

&lt;p&gt;GitHub actions and workflows are written in YAML, a language that is a superset of JSON and is considered easier on the eye. You'll notice that indentations are used instead of curly brackets.&lt;/p&gt;

&lt;p&gt;For GitHub to recognize your &lt;code&gt;.yml&lt;/code&gt; files as workflows you have to store them inside the following folder of your repository: &lt;code&gt;.github/workflows/[workflow-name].yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can add a workflow manually by pushing your own files, or going to the "Actions" tab in your repo and either clicking on "set up a workflow yourself" or selecting one of the available templates GitHub suggests.&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%2Fesqpxzdbg1vmctrvmcmb.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%2Fesqpxzdbg1vmctrvmcmb.png" alt="getting started with github actions" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have at least one workflow, you'll be able to manage them from the same page, as well as dispatch, re-run failed jobs, and view the status of previous runs.&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%2Fa37szwlqpvrzu2aleu56.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%2Fa37szwlqpvrzu2aleu56.png" alt="github actions manage page" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the workflow's structure
&lt;/h2&gt;

&lt;p&gt;Let's examine this basic workflow that says hi to the person who initiated the run and then runs some tests, and understand the different parts that it's constructed from.&lt;br&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;CI&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;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&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;unit-tests&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@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install&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 install&lt;/span&gt;  
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&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 test&lt;/span&gt;
  &lt;span class="na"&gt;e2e-tests&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@v3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install&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 install&lt;/span&gt;  
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&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 e2e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to define the workflow's settings. We can see that this workflow has three properties: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;on&lt;/code&gt;, and &lt;code&gt;jobs&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%2F8jddd2htbf0cmjh26kow.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%2F8jddd2htbf0cmjh26kow.png" alt="workflow basics" width="208" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;name&lt;/code&gt; is simply the workflow's name. It's not mandatory, however, I still recommend adding one, so it'll be easier to manage your workflows in the "Actions" tab.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;on&lt;/code&gt; defines the trigger of the workflow. You can set one or more. For instance, in the example shown above, the workflow will run whenever a pull request is opened or a push to any branch occurs.&lt;/p&gt;

&lt;p&gt;If you want to make your trigger more specific, you can provide extra parameters. Each trigger event is different, so let's have a look at some examples.&lt;/p&gt;

&lt;p&gt;1. &lt;strong&gt;A push to specific branches&lt;/strong&gt;&lt;br&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this one, we want the workflow to run on a push event, but only when the branch name equals the ones we provide using the &lt;code&gt;branches&lt;/code&gt; property. In this case, it's "master" or "test". If we push something to a branch named "test2", nothing will happen.&lt;/p&gt;

&lt;p&gt;By the way, in YAML arrays can be defined with square brackets or like so:&lt;br&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the exact same thing! You might see both styles in use, and it's up to your preference.&lt;/p&gt;

&lt;p&gt;Anyway, we can be even more specific, for instance, mention only branches that start with &lt;code&gt;tests/&lt;/code&gt;:&lt;br&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tests/**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or do the opposite and accept &lt;strong&gt;all&lt;/strong&gt; branches but ignore everything that starts with &lt;code&gt;tests/&lt;/code&gt; by using &lt;code&gt;branches-ignore&lt;/code&gt; instead of &lt;code&gt;branches&lt;/code&gt;&lt;br&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;branches-ignore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tests/**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2. &lt;strong&gt;Scheduled workflow&lt;/strong&gt;&lt;br&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;6&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can make our workflow run automatically on a scheduled basis, using the &lt;code&gt;schedule&lt;/code&gt; trigger. In this example, the workflow will run every day at 6:00 AM. You can see that schedule receives an array, so you can add multiple &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule" rel="noopener noreferrer"&gt;cron settings&lt;/a&gt; if you wish.&lt;/p&gt;

&lt;p&gt;3. &lt;strong&gt;Manual workflow dispatch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another common trigger is &lt;code&gt;workflow_dispatch&lt;/code&gt; which allows us to manually trigger the workflow directly from the GitHub Actions UI. It can even be configured to require parameters that can be later accessed by our actions.&lt;br&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;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sveta&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;caller&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;workflow'&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;print&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print the name&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;echo "Hi there, ${{ inputs.name }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what it looks like inside the GitHub UI:&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%2F233t1webexb2m9z3ex0n.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%2F233t1webexb2m9z3ex0n.png" alt="github ui" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many more possible triggers and configurations, so going to the &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; is the best place to learn more.&lt;/p&gt;

&lt;p&gt;ℹ️ Note&lt;br&gt;&lt;br&gt;
When you see an expression wrapped with &lt;code&gt;${{}}&lt;/code&gt; know that it's a way to access a variable's value, as seen in the example above. This is the way to get &lt;a href="https://docs.github.com/en/actions/learn-github-actions/contexts#github-context" rel="noopener noreferrer"&gt;context&lt;/a&gt; information (like which branch we're on), &lt;a href="https://docs.github.com/en/actions/learn-github-actions/contexts#secrets-context" rel="noopener noreferrer"&gt;secrets&lt;/a&gt;, our workflow's input values, and more.&lt;br&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "Hi there, ${{ inputs.name }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's get things running: the "jobs" property
&lt;/h2&gt;

&lt;p&gt;So up until now, we set up a trigger to our workflow, but now let's get into what the workflows are actually doing - running jobs that trigger our actions!&lt;/p&gt;

&lt;p&gt;When creating a workflow you can set it to run one or more jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unless configured otherwise, jobs run in parallel and don't depend on previous jobs to finish first.&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%2F62e1ukorba3za6pt3nte.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%2F62e1ukorba3za6pt3nte.png" alt="jobs" width="468" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the scenario above, our workflow runs two jobs: "unit-tests" and "e2e-tests", and while the workflow is activated, the jobs will run simultaneously. We will see later how we can create dependencies between jobs.&lt;/p&gt;

&lt;p&gt;To define a job, we first give it an id (can be anything we like), and then we need to provide it with some configuration. &lt;/p&gt;

&lt;p&gt;There are 2 mandatory parameters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;runs-on&lt;/code&gt; : This configures the job's runner. Runners are virtual machines (VMs) used to run the tasks defined in our jobs. GitHub provides hosted runners for each operating system (Linux, macOS, and Windows). You can see the full list of available runners here, as well as their specifications. If you require more granular control over your VM, you can self-host your own runners. One use case for using self-hosted runners is resource utilization. If you need to run your actions on stronger machines, &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners" rel="noopener noreferrer"&gt;explore this option&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;steps&lt;/code&gt; - Here we list the array of actions the job will execute. The steps are executed one by one. We will go over actions in the next section.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some notable optional parameters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; - Just like with workflows, it is not mandatory to provide a name for your job, but it's useful for visualization of your flow. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;needs&lt;/code&gt; - Remember that we said that jobs don't depend on each other, and run in parallel? But we can create this dependency by using the "needs" param. Let's see the example below:
&lt;/li&gt;
&lt;/ol&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;unit-tests&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@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install&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 install&lt;/span&gt;  
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&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 test&lt;/span&gt;
  &lt;span class="na"&gt;e2e-tests&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@v3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install&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 install&lt;/span&gt;  
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&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 e2e&lt;/span&gt;
  &lt;span class="na"&gt;send-slack-notification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;unit-tests&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;e2e-tests&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@v3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send notification&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;rtCamp/action-slack-notify@v2&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;SLACK_WEBHOOK&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK }}&lt;/span&gt;
            &lt;span class="na"&gt;SLACK_CHANNEL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;team-ci&lt;/span&gt;
            &lt;span class="na"&gt;SLACK_TITLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Finished running tests&lt;/span&gt;
            &lt;span class="na"&gt;SLACK_MESSAGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hooray&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;:rocket:'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the last job, &lt;code&gt;send-slack-notification&lt;/code&gt; requires &lt;code&gt;unit-test&lt;/code&gt; and &lt;code&gt;e2e-tests&lt;/code&gt; to finish, since we want to send that slack notification only when both of these jobs are done executing.&lt;/p&gt;

&lt;p&gt;1. &lt;code&gt;if&lt;/code&gt; - We can add a condition to our job that will allow us to set it to run only if some condition/s are met. For instance, let's say that our workflow can be triggered by both push and pull_request events, but we want to run a specific job in this flow that will only run if the trigger was specifically a "push" event.&lt;br&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;Test&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;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&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;print-something-on-push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'push'&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print&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;echo "This job runs on push only".&lt;/span&gt;
  &lt;span class="na"&gt;print-always&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print&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;echo "This job always runs".&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2. &lt;code&gt;outputs&lt;/code&gt; - A job can produce an output that can later be accessed by other jobs (combined with &lt;code&gt;needs&lt;/code&gt; of course, as we have to wait for that job to resolve first). The output is an object, so you can pass any number of parameters that you want.&lt;br&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;Job outputs test&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;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version"&lt;/span&gt;
                &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&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;prepare-version-id&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;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;version_w_hyphens&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.replace-string.outputs.replaced }}&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;frabert/replace-string-action@v2&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;replace-string&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;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\.'&lt;/span&gt;
              &lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.version }}&lt;/span&gt;
              &lt;span class="na"&gt;replace-with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-'&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;print"&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;echo ${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;
    &lt;span class="na"&gt;print-stuff&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;prepare-version-id&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;print&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;another&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;job"&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;echo ${{needs.prepare-version-id.outputs.version_w_hyphens}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we have a workflow that expects a string input called &lt;code&gt;version&lt;/code&gt; on dispatch. &lt;/p&gt;

&lt;p&gt;Then, let's imagine that we need this version for multiple usages, and some of them require us to replace the dots in the string with hyphens.&lt;br&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;prepare-version-id&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;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;version_w_hyphens&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that &lt;code&gt;prepare-version-id&lt;/code&gt; defines the &lt;code&gt;outputs&lt;/code&gt; object, with one item - &lt;code&gt;version_w_hyphens&lt;/code&gt; which returns the value of the step that was responsible for replacing the dots with hyphens. Actions can return output as well, but more on that later.  Then inside the other job called &lt;code&gt;print-stuff&lt;/code&gt; we can access this value by calling &lt;code&gt;needs.[job-id].outputs.[outpus-key]&lt;/code&gt; and in our case &lt;code&gt;needs.prepare-version-id.outputs.version_w_hyphens&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now to the star of the show: Actions
&lt;/h2&gt;

&lt;p&gt;As we stated before, jobs run an array of steps, where each step executes an action, where an action is a set of commands or tasks. There are 3 kinds of actions you can work with.&lt;/p&gt;

&lt;p&gt;1. &lt;strong&gt;Using open-sourced actions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the most part, there's a high probability that someone already has created a solution for at least some of the tasks you wish to accomplish. For instance, if you need to send a slack notification, publish to GitHub pages, upload an artifact, and so on, the community has got you covered.&lt;br&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;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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&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@v3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example of one of the most useful public actions there are, that allows you to checkout to the branch that's in the workflow's context (or to another one if you wish).  All you have to do in order to use such an action is to create a step with the &lt;code&gt;uses&lt;/code&gt; property and provide the action's location, ie &lt;code&gt;[github-user]/[repo]@[version]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can specify a specific version, for example &lt;code&gt;@v3&lt;/code&gt; in that case, or simply refer to the latest possible version by using &lt;code&gt;@master&lt;/code&gt; (though then you're opening yourself to be affected by bugs or breaking changes).&lt;/p&gt;

&lt;p&gt;That's it. You don't have to actually install or configure anything.&lt;/p&gt;

&lt;p&gt;Some actions might expect some input parameters (or have some optional ones). In that case, all you have to do is to add the &lt;code&gt;with:&lt;/code&gt; property to the step and pass the required values.&lt;br&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;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;frabert/replace-string-action@v2&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Replace string&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;replace-string&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;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\.'&lt;/span&gt;
    &lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.version }}&lt;/span&gt;
    &lt;span class="na"&gt;replace-with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some actions might also return some sort of output. For instance, in this example, we use this action to run some regex expression on a string, so naturally, we need the result. To do that we will need to provide an &lt;code&gt;id&lt;/code&gt; to the step, so we can access it later by calling &lt;code&gt;steps.[step-id].outputs.[key]&lt;/code&gt;.&lt;br&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;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;frabert/replace-string-action@v2&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;replace-string&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;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\.'&lt;/span&gt;
      &lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ inputs.version }}&lt;/span&gt;
      &lt;span class="na"&gt;replace-with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;print&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;replaced&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;previous&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;step"&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;echo ${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ You should use caution with 3rd party actions as they may contain malicious code or vulnerabilities that can compromise the security of your project and lead to a data breach or other negative consequences. Make sure to check if the action is properly maintained and has a community base.&lt;/p&gt;

&lt;p&gt;2. &lt;strong&gt;Running shell commands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can also run our own code, by running shell commands. The default depends on the kind of runner you're using. For instance, for Linux (ubuntu) it would use bash. You can change the shell type by providing an explicit one. See all the possible shells &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&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;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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run install&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 install&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt; &lt;span class="c1"&gt;#an optional setting&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run a multiline script, we can use a pipeline, like so:&lt;br&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;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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run install and test&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;npm install    &lt;/span&gt;
        &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case we want our action to provide an output that can be accessed by other actions, we have to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set output&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;echo "{name}={value}" &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can set as many as we want. Accessing the values from other steps follows the same convention as mentioned in the previous section.&lt;br&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;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;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "animal='Dog'" &amp;gt;&amp;gt; $GITHUB_OUTPUT  &lt;/span&gt;
      &lt;span class="s"&gt;echo "name='Fluffy'" &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "Animal type: ${{steps.example.outputs.animal}}"&lt;/span&gt;
      &lt;span class="s"&gt;echo "Animal name: ${{steps.example.outputs.name}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3. &lt;strong&gt;Running an action from a file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's say we have a custom-made action that we use in multiple workflows and we don't want to repeat writing. In that case, we can create an action.yml file and store it inside our repo inside the following path: &lt;code&gt;.github/actions/[action-id]/action.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example action that's using the composite action method where you can create an action with the regular YML syntax and run one or more steps:&lt;br&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;My&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Action'&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;An&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;example&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;custom&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;action'&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;print'&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composite&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo Hello ${{ inputs.message }}.&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can refer to it by calling it like this:&lt;br&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;My Workflow&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&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;print-message&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print message&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;./.github/actions/my-action&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;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;world!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are other methods to create actions, where you create the action.yml file just to set up the input and output params and the script itself is written in other languages of your choice (JS, python, shell, and more). You can read about it &lt;a href="https://docs.github.com/en/actions/creating-actions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some other action settings
&lt;/h2&gt;

&lt;p&gt;Actions have some other parameters that are worth mentioning.  Of course, the &lt;code&gt;name&lt;/code&gt; parameter, which again will make it easier to follow in the log, but the most useful one is &lt;code&gt;if&lt;/code&gt;. We already discussed it as a possible parameter for jobs, but actions can also be limited to running only on condition.&lt;/p&gt;

&lt;p&gt;One of the useful conditions we can check for is the job's status. For instance, send a failure message to Slack, but only when the job has failed. See the full list of status checks &lt;a href="https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;- name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The job has succeeded&lt;/span&gt;
    &lt;span class="s"&gt;if&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ success() }}&lt;/span&gt;
    &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# do something if all the previous steps have finished successfuly&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The job has failed&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ failure() }}&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# do something if the job has filed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another useful action property is &lt;code&gt;continue-on-error&lt;/code&gt;. By default, if one step of a job failed, it will cause the entire job to end with the "failure" status. However, sometimes we might want to not count this failure as part of the whole job's status. In that case, we can pass this property to make the run ignore this step's status.&lt;br&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;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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ignore my failure&lt;/span&gt;
    &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing our workflow
&lt;/h2&gt;

&lt;p&gt;So now that we have a workflow, how do we actually test it? Well, it's simple and tricky at the same time. To be able to run a workflow its file must either exist on the master/main branch or use a trigger that occurs when pushing to the branch we're writing our action on.&lt;/p&gt;

&lt;p&gt;If the workflow happens to have a &lt;code&gt;worflow_dispatch&lt;/code&gt; trigger and we want to try some changes, we can apply them to a branch, add initiate the workflow from our branch.&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%2F64jqrxky44f93yawq3z7.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%2F64jqrxky44f93yawq3z7.png" alt="workflow dispatch" width="393" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also another way that allows you to run actions locally on your machine, but it's a little trickier to set up. You can read about it &lt;a href="https://github.com/nektos/act" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that's it! These were the basics of what you need to know to get started with GitHub actions. Hope you will find it useful!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devto</category>
      <category>announcement</category>
      <category>community</category>
    </item>
    <item>
      <title>Understanding the difference between useMemo and useCallback</title>
      <dc:creator>Sveta Slepner</dc:creator>
      <pubDate>Sun, 05 Feb 2023 20:23:13 +0000</pubDate>
      <link>https://dev.to/svetaslepner/understanding-the-difference-between-usememo-and-usecallback-12nj</link>
      <guid>https://dev.to/svetaslepner/understanding-the-difference-between-usememo-and-usecallback-12nj</guid>
      <description>&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%2Fdkilgimiyrlxvigsmnx2.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%2Fdkilgimiyrlxvigsmnx2.jpg" alt="chemex" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React library provides us two built-in hooks to optimize the performance of our app: useMemo &amp;amp; useCallback. At first glance, it might look like their usage is quite similar, so it can get confusing about when to use each. To clear that confusion, let’s dig in and understand the actual difference and the correct way to use them both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functional components have a problem
&lt;/h2&gt;

&lt;p&gt;Functional components are great. Their combination with hooks allows for much more code reusability and flexibility than Class components. However, they do have one problem: A functional component is the same as the render function we used to have in class components. It’s a function that is being re-run on any prop/state change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It means that:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A. If a function is called inside the component, it will be re-evaluated, again and again, on every re-render.&lt;/p&gt;

&lt;p&gt;B. If a function is created inside the component is passed to a child component, it will be recreated, meaning the pointer will change, causing the child to re-render or call the function unnecessarily (depending on the situation).&lt;/p&gt;

&lt;p&gt;To tackle the problem and prevent the possible performance issue, React provides us with two hooks: useMemo and useCallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  useMemo
&lt;/h2&gt;

&lt;p&gt;Let’s start with the first problem and see how we can prevent evaluating functions unnecessarily.&lt;/p&gt;

&lt;p&gt;In the following demo, we have a component with two states: one store a number, and the other one a boolean. We need to do some calculation on the number we have in our state, so we call our plusFive function and render the result.&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;plusFive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I was called!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&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="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;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNum&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="mi"&gt;0&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;light&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLight&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="kc"&gt;true&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;numPlusFive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;plusFive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/use-memo-no-memo-g959e"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you open the console, you’ll see that plusFive is called whether we click on “Update Number” which sets a new number, or “Toggle the light” which updates the boolean state (and has nothing to do with numPlusFive).&lt;/p&gt;

&lt;p&gt;So how can we prevent this from happening? By memoizing &lt;code&gt;plusFive&lt;/code&gt; ! Until we will receive a new number, the function will not be called. The calculation is skipped, and we will receive the result immediately.&lt;/p&gt;

&lt;p&gt;We will do that by using &lt;code&gt;useMemo&lt;/code&gt; , and it will 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numPlusFive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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;plusFive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;useMemo receives two parameters: A function that returns our function call, and an array of dependencies. Only when one of the dependencies is changed, our function will be called again. useMemo returns the results of that function execution and will store it in memory to prevent the function from running again if the same parameters were used.&lt;/p&gt;

&lt;p&gt;Go ahead and see for yourself (don’t forget to open the console):&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/use-memo-tsc89"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  useCallback
&lt;/h2&gt;

&lt;p&gt;Now that we know how to prevent re-evaluating functions, let’s see how we can prevent functions created inside components from being recreated on every render.&lt;/p&gt;

&lt;p&gt;In the demo below, we have a child component () that receives as a prop, a function we created inside the parent component (). Note this function is being used inside a useEffect hook, and since it’s listed as useEffect’s dependency, it’s being called again. Yes, even when we change other states or receive props, not related to our “plusFive” function.&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;App&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;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNum&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="mi"&gt;0&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;light&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLight&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="kc"&gt;true&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;plusFive&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I was called!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&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;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;light&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&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;dark&lt;/span&gt;&lt;span class="dl"&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;div&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;SomeComp&lt;/span&gt; &lt;span class="nx"&gt;someFunc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;plusFive&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&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;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&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="nf"&gt;setLight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;light&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;Toggle&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;light&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&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;/div&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;/div&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SomeComp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;someFunc&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;calcNum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCalcNum&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="mi"&gt;0&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;// In this scenatio, someFunc will change on every render, so this useEffect will run.&lt;/span&gt;
     &lt;span class="nf"&gt;setCalcNum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;someFunc&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;someFunc&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Plus&lt;/span&gt; &lt;span class="na"&gt;five&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;calcNum&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;/span&amp;gt;&lt;/span&gt;&lt;span class="err"&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;iframe src="https://codesandbox.io/embed/use-callback-no-callback-h6x4m"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;To prevent our function from being recreated and change pointers on each render round, we can use &lt;code&gt;useCallback&lt;/code&gt;. This React hook receives two parameters: A function and an array of dependencies:&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;plusFive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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;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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I was called!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&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;num&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hook lets us preserve the function, and it will be recreated only when one of its dependencies changes.&lt;/p&gt;

&lt;p&gt;Here’s the working demo:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/use-callback-ymhyy"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  But Wait! Don’t misuse these hooks!
&lt;/h2&gt;

&lt;p&gt;While these two hooks provide a solution to a real problem, they may get misused very easily and even cause more harm.&lt;/p&gt;

&lt;p&gt;For instance, there is no need to memoize a function that’s doing some basic calculation (like in the demo). Only use &lt;code&gt;useMemo&lt;/code&gt; whenver you’re trying to prevent re-running expensive functions, that run a lot of time, or using a lot of resources. Why? Because useMemo keeps in memory the results of the functions execusion, and it might potentially grow big and ironically harm the performance of your App.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;useCallback&lt;/code&gt; things might get even worse: when not using useCallback, your old function will be garbage collected, but with useCallback it will stay in memory, in case one of the dependencies will be right again to return that old function version.&lt;/p&gt;

&lt;p&gt;So when is it right to use &lt;code&gt;useCallback&lt;/code&gt; ? When you actually see that not using it harms your performance, or will result in an unneccery heavy function execution (imagine in the useCallback demo, that this function performs an API call, and not just adding numbers. This is something worth preventing).&lt;/p&gt;

&lt;h2&gt;
  
  
  To summarise:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;useMemo&lt;/strong&gt; keeps a function from being executed again if it didn’t receive a set of parameters that were previously used. It returns the results of a function. Use it when you want to prevent some heavy or costly operations from being called on each render.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;useCallback&lt;/strong&gt; keep a function from being re-created again, based on a list of dependencies. It returns the function itself. Use it when you want to propagate it to child components, and prevent from a costly function from re-running.&lt;/p&gt;

</description>
      <category>devto</category>
      <category>offers</category>
      <category>announcement</category>
    </item>
    <item>
      <title>The Complete Guide to Front-end Developer Interviews</title>
      <dc:creator>Sveta Slepner</dc:creator>
      <pubDate>Wed, 01 Feb 2023 19:11:55 +0000</pubDate>
      <link>https://dev.to/svetaslepner/the-complete-guide-to-front-end-developer-interviews-4jcd</link>
      <guid>https://dev.to/svetaslepner/the-complete-guide-to-front-end-developer-interviews-4jcd</guid>
      <description>&lt;p&gt;Interviews are hard, especially technical interviews where you’re expected to think, solve, and analyze all while the interviewer stares at you. But what people don’t realize is that being interviewed is basically just another skill, and skills can be honed with the right information and practice.&lt;/p&gt;

&lt;p&gt;So if you’re on your job hunt as a Front-end developer right now, you’ve come to the right article, as this one will tell you all you need to know to be prepared!&lt;/p&gt;

&lt;p&gt;About a year and a half ago, the company I used to work for was shut down, and all 100 employees found themselves seeking a new place. I worked there for more than 9 years, so starting a job hunt was unsettling. I knew that my JS skills are (probably) fine, but I didn’t know what to expect during technical interviews.&lt;/p&gt;

&lt;p&gt;So based on my own experience, the experiences of my colleagues who shared the same fate, as well as my current practice as an interviewer myself, I decided to write down this article. It is my hope that it will help you prepare, and take away some of the concerns you might have about what awaits you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Kind of Questions Should You Expect?
&lt;/h2&gt;

&lt;p&gt;Each company has its own interviewing strategy, but in the end, most of them fall under the same categories, and it doesn’t matter if you’re interviewing to GAFAM or a small tech company. These are the most common topics you’ll be interviewed about:&lt;/p&gt;

&lt;h2&gt;
  
  
  Javascript Questions
&lt;/h2&gt;

&lt;p&gt;Well, as a front-end developer you obviously should know Javascript already, but you’re also expected to understand how it works and behaves. It doesn’t matter if in your day-to-day you work with Angular/React/Vue, you are expected to know the basics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some example questions could be:&lt;/strong&gt;&lt;br&gt;
A. Explain what the event loop is&lt;br&gt;
B. Explain what a Promise is&lt;br&gt;
C. Closure and Context questions (what is “this”)&lt;br&gt;
D. What is the difference between an arrow function and a regular function?&lt;br&gt;
E. Implement Array.prototype.map/reduce&lt;br&gt;
F. What is a debounce/throttle function? Implement them.&lt;br&gt;
G. Javascript prototypal inheritance questions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some helpful resources:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.sitepoint.com/5-typical-javascript-interview-exercises/" rel="noopener noreferrer"&gt;5 Typical JavaScript Interview Exercises&lt;/a&gt;&lt;br&gt;
&lt;a href="https://johnresig.com/apps/learn/" rel="noopener noreferrer"&gt;Learning Advanced JavaScript&lt;/a&gt;&lt;br&gt;
&lt;a href="http://bonsaiden.github.io/JavaScript-Garden/" rel="noopener noreferrer"&gt;Javascript Garden&lt;/a&gt;&lt;br&gt;
&lt;a href="https://eloquentjavascript.net/" rel="noopener noreferrer"&gt;Eloquent Javascript&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Algorithms
&lt;/h2&gt;

&lt;p&gt;It is true that it’s unlikely you’ll ever need to traverse a binary tree while working as a Front-end developer (there are exceptions of course). But nonetheless, algorithm questions are very popular in interviews (especially if your goal is to work at GAFAM).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Array or Object related questions&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reverse a string&lt;/li&gt;
&lt;li&gt;Write a function that checks if a word is a palindrome&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Given a string of characters, return the character that appears the most often.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BFS/DFS questions (traversing a tree)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Write a function that solves a maze (the maze is a multidimensional array- with values of 0 — wall, 1 — floor, 2 — exit). The function receives a start coordinate and should return whether you can get out of the maze.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Linked List&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reverse a linked list&lt;/li&gt;
&lt;li&gt;Find the nth node from the end of the linked list&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should also probably refresh your knowledge about the difference between Recursion and Iteration and about Time and Space complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some helpful resources:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://medium.com/siliconwat/algorithms-in-javascript-b0bed68f4038" rel="noopener noreferrer"&gt;40 Problems, Solutions, and Explanations&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.udemy.com/course/js-algorithms-and-data-structures-masterclass/" rel="noopener noreferrer"&gt;JavaScript Algorithms and Data Structures Masterclass&lt;/a&gt; — (Note: This one is no doubt the best Udemy course ever created, especially if you don’t have a degree in Computer Sciences, or if you need a refresher about algorithms and data structures).&lt;br&gt;
&lt;a href="https://www.codewars.com/" rel="noopener noreferrer"&gt;Codewars&lt;/a&gt; (or any other equivalent site, like HackerRank or LeetCode).&lt;/p&gt;

&lt;h2&gt;
  
  
  What To Pay Attention To When Solving an Algorithm Question
&lt;/h2&gt;

&lt;p&gt;A. Don’t rush to solve, it’s ok to ask for a few minutes to think.&lt;/p&gt;

&lt;p&gt;B. When you do start solving, it is highly recommended that you talk about what you’re doing, even if you’re not sure about your thoughts. The examiner usually looks to understand your process of thinking. It is not always necessary to reach a perfect and working solution. If you’re not comfortable talking aloud, or just not used to it, practice at home by solving some example questions.&lt;/p&gt;

&lt;p&gt;C. If you can, you should first write your plan of action in words or pseudo-code. This will show the interviewer that you do not rush to solve things and that you can plan.&lt;/p&gt;

&lt;p&gt;D. If you get stuck at the beginning, don’t panic! Start with the simple things. Think about input and output. Solve edge cases.&lt;/p&gt;

&lt;p&gt;E. Pay attention to the code effectiveness of your solution. If you understand that the complexity is not really good, say it out loud, and try together with the examiner to reach a better solution.&lt;/p&gt;

&lt;p&gt;F. It’s totally fine to ask questions. A good examiner will try to help you reach a solution.&lt;/p&gt;

&lt;p&gt;G. You’re usually expected to solve these type of questions on a whiteboard/piece of paper. Since it’s not how we usually write code, you may find it’s harder to think like this. This is again something that worth practicing beforehand!&lt;/p&gt;

&lt;h2&gt;
  
  
  React/Angular/Vue (Home) Assignment
&lt;/h2&gt;

&lt;p&gt;Some places will require you to build some sort of a simple app using a specific framework/library. Depending on the company, it can either be a home assignment, or you’ll have to do so while in the companies office. If it’s the latter, bring your own laptop, so you can use your own familair IDE and operating system.&lt;/p&gt;

&lt;p&gt;In most cases, you’ll be given some sort of public API and be required to work with it in some way.&lt;/p&gt;

&lt;p&gt;This is done to see the way the candidate writes actual code, so here are some things to pay attention to:&lt;/p&gt;

&lt;p&gt;A. Keep your code clean. Use indentation, provide meaningful variable names, remove unused code.&lt;/p&gt;

&lt;p&gt;B. Use best practices of the given framework.&lt;/p&gt;

&lt;p&gt;C. Think about things like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Debounce requests sent to the server.&lt;/li&gt;
&lt;li&gt;Prevent server calls when &amp;lt; 3 characters are typed.&lt;/li&gt;
&lt;li&gt;Take care of edge cases like missing information from the API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;D. Your CSS skills are important too! Be comfortable with using Flexbox (don’t use float to align containers 😉).&lt;/p&gt;

&lt;h2&gt;
  
  
  Logic Questions
&lt;/h2&gt;

&lt;p&gt;I admit. I really dislike this type of question myself. I don’t understand how they can help anyone evaluate your value as a developer. But some companies still ask them…&lt;br&gt;
You can’t really prepare for these ones (maybe read about some common questions?), but just know that they do exist.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
You are standing in a room with three light switches. The switches all correspond to three different light bulbs in a nearby room that you cannot see into, but you can go in one time only. With all the light switches starting in the off position, how can you find out which switch connects to which light bulb?&lt;/p&gt;

&lt;h2&gt;
  
  
  Talking About Yourself
&lt;/h2&gt;

&lt;p&gt;Last but not least, there’s a part where you need to talk about your past experience.&lt;/p&gt;

&lt;p&gt;If you’re applying to your first job as a developer, make sure to have some project you’re passionate about or maybe contribute to some open-source library.&lt;/p&gt;

&lt;p&gt;Be ready to discuss the nitty-gritty. For example, why did you choose library A instead of B?&lt;/p&gt;

&lt;p&gt;If this isn’t your first rodeo, you will need to talk about a feature or product that you were responsible for at work. &lt;strong&gt;In details.&lt;/strong&gt; The Interviewer would also likely want to hear about your personal contribution to the team.&lt;/p&gt;

&lt;p&gt;You should practice this conversation with a friend so that you have feedback! It would be so much easier for you if you come prepared.&lt;/p&gt;

&lt;h2&gt;
  
  
  And Most Importantly: A Failed Interview does NOT Define You!
&lt;/h2&gt;

&lt;p&gt;Remember, a failed interview doesn’t say anything about how good a developer you are. As I mentioned in the beginning, interviewing is a skill of its own. In your day-to-day life, you have StackOverflow and co-workers at your disposal, and you’re not expected to write code on a piece of paper. Interviews are simply not something you’re used to doing, so you need to try it a few times to grasp how it’s done. Prepare and study, but don’t be hard on yourself if you don’t pass. Try to learn something from each interview, and eventually, you will succeed!&lt;/p&gt;

&lt;p&gt;Good luck! :)&lt;/p&gt;

&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@wocintechchat?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Christina @ wocintechchat.com&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/interview?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting Started With Three.js</title>
      <dc:creator>Sveta Slepner</dc:creator>
      <pubDate>Tue, 31 Jan 2023 21:46:18 +0000</pubDate>
      <link>https://dev.to/svetaslepner/getting-started-with-threejs-1b25</link>
      <guid>https://dev.to/svetaslepner/getting-started-with-threejs-1b25</guid>
      <description>&lt;p&gt;The ability to render 3D objects in the browser opens up many exciting possibilities for creating interactive experiences. Whether you’re looking for a new way to showcase products on your e-commerce site, creating stunning landing pages, or maybe even developing a game.&lt;/p&gt;

&lt;p&gt;Since handling WebGL directly (JavaScript API for rendering interactive 2D and 3D graphics within any compatible web browser) can be complex, libraries, such as three.js, provide a simplified way to deal with rendering, animating, and interacting with 3D objects, while doing all the heavy lifting behind the scenes.&lt;/p&gt;

&lt;p&gt;With that being said, three.js itself can still be a little overwhelming for developers who have never dealt with 3D before. Hopefully, this article will get you up to speed and present the necessary basis, that may assist you even if you’ll require more advanced features later on.&lt;/p&gt;

&lt;p&gt;What does it take to render a simple cube?&lt;br&gt;
The reason why working with 3D for a web developer might be confusing at first, is that even a simple task such as rendering a cube requires some knowledge in 3D jargon.&lt;/p&gt;

&lt;p&gt;If for instance, someone tells you, the web developer, to render a red box, I bet what you have in mind is “ok, I’ll create a div, use some CSS to size, place, and color it”. Pretty straightforward.&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%2Foeay6m95y897qsfyxtya.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%2Foeay6m95y897qsfyxtya.jpg" alt="A simple red box created with css" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, to do the same in 3D will require you to:&lt;br&gt;
A. Create something called a “scene”&lt;br&gt;
B. Define a cube geometry&lt;br&gt;
C. Create a material and attach it to the cube (to make it red)&lt;br&gt;
D. Create a camera&lt;br&gt;
E. Add lighting&lt;br&gt;
F. Tell three.js to render all that&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/basic-three-js-3z9rr"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The scene
&lt;/h2&gt;

&lt;p&gt;In three.js, a scene is like a container that holds all the objects used to render our 3D image. Think about a theatre stage, where we place the actors, the set, and the lighting.&lt;br&gt;
In the same manner, we assign 3D objects and lighting to a scene.&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="c1"&gt;// Creating a scene&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scene&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Scene&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;geometry&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BoxGeometry&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="mi"&gt;10&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;material&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MeshStandardMaterial&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;0xff0000&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;cube&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mesh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;material&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Assigning a 3D object to our scene&lt;/span&gt;
&lt;span class="nx"&gt;scene&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="nx"&gt;geometry&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;directionalLight&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DirectionalLight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xffffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;directionalLight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&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;2&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="c1"&gt;// Adding a light source to our scene&lt;/span&gt;
&lt;span class="nx"&gt;scene&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="nx"&gt;directionalLight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like we might have multiple stage sets in our theatre, each showing a different play, we can create multiple scenes and switch between them, or render them simultaneously.&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%2Fpw4y7z0n129w1r0u2rbf.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%2Fpw4y7z0n129w1r0u2rbf.png" alt="Origin: https://threejs.org/examples/?q=camera#webgl_camera" width="688" height="562"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://threejs.org/examples/?q=camera#webgl_camera" rel="noopener noreferrer"&gt;https://threejs.org/examples/?q=camera#webgl_camera&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3D geometry
&lt;/h2&gt;

&lt;p&gt;A 3D geometry is basically a set of instructions for “how to create a 3D shape”. It consists of faces, edges, and vertices.&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%2Faotqw33lcr8ny85jeaap.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%2Faotqw33lcr8ny85jeaap.jpg" alt="Source: https://en.wikipedia.org/wiki/Polygon_mesh" width="720" height="271"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://en.wikipedia.org/wiki/Polygon_mesh" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Polygon_mesh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, three.js provides us with some built-in geometry classes, such as BoxGeometry, SphereGeometry, CylinderGeometry, and so on.&lt;/p&gt;

&lt;p&gt;For example, to create a simple box, all we need to do is to provide the width, height, and depth. We don’t need to delve into the complexities of defining all the faces ourselves.&lt;/p&gt;

&lt;p&gt;The size unit used in three.js represents meters, so 1 unit = 1 meter.&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;geometry&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BoxGeometry&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="mi"&gt;10&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;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fu60eiyzo4iutp3412tt0.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%2Fu60eiyzo4iutp3412tt0.jpg" alt="3D Shapes" width="697" height="503"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://en.wikipedia.org/wiki/Shape" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Shape&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you’re not happy with the existing geometries or need to create your own geometry classes, it is very possible. You can see some examples provided by three.js &lt;a href="https://github.com/mrdoob/three.js/tree/dev/examples/jsm/geometries" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Materials
&lt;/h2&gt;

&lt;p&gt;Imagine holding two cubes in your hands, one made from glass, and the other from concrete. Both maybe have the same shape, but they look different and have distinct physical attributes such as reflectiveness, surface, and opacity.&lt;/p&gt;

&lt;p&gt;In the 3D world, we use materials to define such attributes for our 3D objects.&lt;/p&gt;

&lt;p&gt;With three.js we can either create our own materials with the built-in Material classes (such as MeshMatcapMaterial or MeshLambertMaterial), each has its own attributes, or load materials externally using MaterialLoader.&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="c1"&gt;// A basic material, just coloring our cube red&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;material&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MeshStandardMaterial&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;0xff0000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Texture maps are also worth mentioning. These are image files that can be used to define much more detailed materials, and make them look real. There are many types of texture maps, such as “diffuse map” which defines the colors, or the “normal map” which defines the surface of our object. Typically multiple texture maps are applied together. &lt;a href="https://conceptartempire.com/texture-maps/" rel="noopener noreferrer"&gt;This great article&lt;/a&gt; explains each texture map in detail.&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%2Fb27krogq9u1118elpxrn.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%2Fb27krogq9u1118elpxrn.png" alt="Multiple texture maps are used to define the realistic texture of a ball of grass and soil&amp;lt;br&amp;gt;
" width="800" height="436"&gt;&lt;/a&gt;&lt;br&gt;
Multiple texture maps are used to define the realistic texture of a ball of grass and soil&lt;/p&gt;
&lt;h2&gt;
  
  
  Mesh
&lt;/h2&gt;

&lt;p&gt;A mesh is an object representing part of the model. It contains a geometry and its material. A 3D model can be constructed from multiple meshes.&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%2Fv2nwokb79anw1jlq9i6r.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%2Fv2nwokb79anw1jlq9i6r.png" alt="Each highlighted part is a mesh. All meshes combined define the model" width="711" height="354"&gt;&lt;/a&gt;&lt;br&gt;
Each highlighted part is a mesh. All meshes combined define the model.&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;geometry&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BoxGeometry&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="mi"&gt;10&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;material&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MeshStandardMaterial&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;0xff0000&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;cube&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mesh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;material&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Loaders
&lt;/h2&gt;

&lt;p&gt;Sometimes we would like to import 3D models from existing files created by 3D modeling programs, and not create them from scratch. For that, we can use loaders, which are functions that are responsible for loading such files and converting them into three.js objects.&lt;/p&gt;

&lt;p&gt;There is a different loader for each separate type of 3D file. For instance, loading a GLTF file would 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GLTFLoader&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;three/examples/jsm/loaders/GLTFLoader.js&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;loader&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;GLTFLoader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// resource URL&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://somesite.com/3dmodels/fox.gltf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// called when the resource is loaded&lt;/span&gt;
    &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;gltf&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="nx"&gt;scene&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="nx"&gt;gltf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// called while loading is progressing&lt;/span&gt;
    &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;xhr&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&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="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;xhr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;xhr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;% loaded&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="c1"&gt;// called when loading has errors&lt;/span&gt;
    &lt;span class="nf"&gt;function &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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An error happened&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;Did you notice that the GLTFLoader class is not imported from the “three” packages directly but from some mysterious “examples” folder? This is because loaders are not part of the core three.js library, but an extension. Despite the misleading name (“examples”), this folder contains some official extensions, that are maintained together with the base package.&lt;/p&gt;

&lt;p&gt;The idea is that if you’re not happy with one of them, or need some extra features, you can simply copy these files to your project and modify them as you see fit. Of course, you can also use loaders or other extensions made by other developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera
&lt;/h2&gt;

&lt;p&gt;A camera is like a window to our scene. Without a camera defined, we simply see nothing. When defining a camera we create what is called a “frustum” — a mathematical term for a four-sided rectangular pyramid with the top cut off.&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;perspectiveCamera&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PerspectiveCamera&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// fov — Camera frustum vertical field of view.&lt;/span&gt;
  &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// aspect — Camera frustum aspect ratio.&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// near — Camera frustum near plane.&lt;/span&gt;
  &lt;span class="mi"&gt;2000&lt;/span&gt; &lt;span class="c1"&gt;// far — Camera frustum far plane.&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://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%2Fqxp2h5xggokj4f0z8ijc.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%2Fqxp2h5xggokj4f0z8ijc.png" alt="A frustrum" width="720" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are multiple types of cameras in three.js, but the two most useful ones are the perspective camera and the orthographic camera.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Perspective camera&lt;/strong&gt; — In this mode, depth perception is emulated in order to reflect the way the human eye perceives the world. For example, if one cube is positioned closer to us than the other, it will appear to be larger. This is the most common camera you’ll probably use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orthographic camera&lt;/strong&gt; — With the orthographic camera, there is no depth perception, so no matter where the object is placed in the scene, it will look the same size. This is useful for isometric games, for instance.&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%2Fjoh2at2p15rxzdi0bsip.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%2Fjoh2at2p15rxzdi0bsip.png" alt="An isometric video game using an orthographic camera" width="640" height="480"&gt;&lt;/a&gt;&lt;br&gt;
An isometric video game using an orthographic camera&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/orthographic-and-perspective-fd99jm"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Lighting
&lt;/h2&gt;

&lt;p&gt;Just like in real life, without lights, our scene would become pitch black.&lt;/p&gt;

&lt;p&gt;Three.js has multiple built-in light sources we can use and even combine to create the perfect setting.&lt;/p&gt;

&lt;p&gt;It’s worth noting that some light classes support casting shadows, while some don’t, and it depends on their physics. For instance, “Dynamic Light” is a light that gets emitted in a specific direction. This light will behave as though it exists infinitely far away and the rays produced from it are all parallel. A common use case for this is to simulate daylight. Since it’s a one-directional light, it can emit shadows.&lt;/p&gt;

&lt;p&gt;The AmbientLight on the other hand is a light that globally illuminates all objects in the scene equally. Since every spot in the scene receives the same amount of light, AmbientLight can’t be used to cast shadows.&lt;/p&gt;

&lt;p&gt;When defining a light we would usually provide color and intensity.&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;directionalLight&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DirectionalLight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xffffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;directionalLight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&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;2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lights can also come from external sources, like HDR files (An HDR is a 360-degree high dynamic range image wrapped around a 3D model.)&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/three-js-lighting-and-hdr-loader-eiomr5"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Shadows
&lt;/h2&gt;

&lt;p&gt;Casting shadows is a pretty expensive calculation, so in three.js it’s turned off by default. In order to support it we will need to:&lt;/p&gt;

&lt;p&gt;A. Turn on shadow support for the renderer (see next section about what a renderer is). We will also need to provide a type of shadow map, each provides a little different effect and calculation efficiency. See the details &lt;a href="https://threejs.org/docs/#api/en/constants/Renderer" rel="noopener noreferrer"&gt;here&lt;/a&gt; under “Shadow Types”.&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;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PCFSoftShadowMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;B. Tell each individual mesh if it should emit and/or receive shadows.&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;cube&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Mesh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;material&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;castShadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receiveShadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;C. Allow the light source to cast a shadow. We also should provide the shadow map size and bias, which modifies the shadows pixelation.&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;spotLight&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SpotLight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xffffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// make it cast shadows&lt;/span&gt;
&lt;span class="nx"&gt;spotLight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;castShadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;spotLight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mapSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;spotLight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mapSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;spotLight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/three-js-shadow-vuulk9"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Renderer
&lt;/h2&gt;

&lt;p&gt;The render class is used for… well… rendering all of the scene components into the canvas element. This one is pretty straightforward.&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="c1"&gt;// define the renderer&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WebGLRenderer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;antialias&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;alpha&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="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPixelRatio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;devicePixelRatio&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// append the rendered to the dom&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;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// render the scene&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need to provide the desired canvas size using the setSize property, and the pixel density of the device. Note that in a case where the size of the canvas is responsive and depends on the page size, we should update the renderer and camera on window resize.&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;function&lt;/span&gt; &lt;span class="nf"&gt;onWindowResize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aspect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateProjectionMatrix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&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;h2&gt;
  
  
  Animating
&lt;/h2&gt;

&lt;p&gt;More often than not, we’re not going to use three.js just to render one static 3D image. We would want the user to interact with the scene or create animations. To make three.js re-render the canvas, we would need to call renderer.render(scene, camera); each time.&lt;/p&gt;

&lt;p&gt;If our changes are frequent, however, for instance when we add an auto rotation effect to our scene, we can simply do something 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;function&lt;/span&gt; &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Schedual the next update&lt;/span&gt;
   &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Some other changes that should occur on animate&lt;/span&gt;
   &lt;span class="c1"&gt;// for instance, here we can rotate the cube a litle on every frame&lt;/span&gt;
   &lt;span class="nx"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c1"&gt;// re-render&lt;/span&gt;
   &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;animate&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 also required to support loaded 3D files which come with their own animation.&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%2Fd637v24968sx2spc1l80.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%2Fd637v24968sx2spc1l80.gif" alt="Animation loop from file&amp;lt;br&amp;gt;
" width="600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Camera controls
&lt;/h2&gt;

&lt;p&gt;Camera control is another type of extension that adds a layer of interactivity to our scene, allowing the users to zoom in and out, rotate the scene or even navigate within it.&lt;/p&gt;

&lt;p&gt;Let’s take as an example one of the more common camera controls: the orbit controls, which just by defining them lets the user rotate and zoom into the scene.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const orbitControls = new OrbitControls(camera, renderer.domElement);&lt;/code&gt;&lt;br&gt;
Orbit controls have some other neat features out of the box, like adding autorotation to the scene.&lt;/p&gt;

&lt;p&gt;Note that you will have to add &lt;code&gt;orbitControls.update()&lt;/code&gt; to your animate function in order to support it.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/three-js-controls-bqov8b"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Mouse events
&lt;/h2&gt;

&lt;p&gt;Three.js essentially rendered a canvas, and as such, picking up mouse events is trickier than what you might be used to.&lt;/p&gt;

&lt;p&gt;So what happens if you need to track clicks or hover over a 3d object? That’s what the Raycaster class is for. Raycasting is used for working out what objects in the 3d space the mouse is interacting with.&lt;/p&gt;

&lt;p&gt;Here’s a basic example of how to pick up clicked on objects:&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="c1"&gt;// Raycaster&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raycaster&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Raycaster&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;pointer&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;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector2&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;intersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pointerPos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;raycaster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFromCamera&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pointerPos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;raycaster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intersectObjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&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;event&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;// calculate pointer position in normalized device coordinates&lt;/span&gt;
    &lt;span class="nx"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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="nx"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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="c1"&gt;// calculate objects intersecting the picking ray&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intersectedObjects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;intersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pointer&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;intersectedObjects&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;// do something with the objects our mouse intercted with&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 a demo, so you can see it in action:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/raycaster-three-js-t72zu3"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And that should cover all the basics. Hopefully, three.js makes a little more sense now!&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra read
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://discoverthreejs.com/" rel="noopener noreferrer"&gt;https://discoverthreejs.com/&lt;/a&gt; — An amazing free online three.js book and guide. A great resource to learn from.&lt;br&gt;
&lt;a href="https://threejs.org/examples" rel="noopener noreferrer"&gt;https://threejs.org/examples&lt;/a&gt; — the three.js documentation is not beginner-friendly, but it does worth using the examples section to get ideas and learn about more complex topics.&lt;/p&gt;

</description>
      <category>gemini</category>
      <category>ai</category>
      <category>nlp</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
