DEV Community

Cover image for Tech Talk: React in the Terminal? Hold my Beer 🍺
Manuel Artero Anguita 🟨
Manuel Artero Anguita 🟨

Posted on

Tech Talk: React in the Terminal? Hold my Beer 🍺

My company organizes a big event once per year. Around ~600 attendees. There are five simultaneous tracks for keynotes; Product, Project management, Design, Dev, Devops... It's the main event of the season for us.

You get the idea.


This year i decided to present a tech talk. 45 min long. The complete thing: slides & live coding.

I named it: «React in the Terminal? Hold my beer 🍺»


While the slides are in English, i'm afraid the talk itself was in my mother language (πŸ‡ͺπŸ‡Έ) and i won't share the recording.

However, here are the resources I used for the talk:

  1. The slides: up & running hosted at Vercel; I used SliDev, a framework that turns markdown into a web app which behaves like a Keynote. It's pretty cool.
    I genuinely think SliDev deserves its own post someday πŸ€”.

  2. my-react-dom: Repository with a custom implementation of react-dom used to live coding. Two branches: playground and main

  3. ink-world: Repository for a tiny-tiny-tiny game using Ink + React on the terminal again, used to live coding. Two branches: playground and main.


Talk Recap

I led a quick journey, starting with the simplest Β«Hello WorldΒ» in React...

...But unrolling the jsx syntax, making more obvious where we're invoking react and where we are calling react-dom

Slide no 7

This led us to the question: why are react and react-dom separated into two different packages?

We discussed the philosophy that React embraces; they mention "interfaces" and how React is designed to plug into any interface.

Slide no. 8

Next step: react-reconciler: the package the React team provides to create your custom renderer.

Slide no. 9

Time to live coding session (my-react-dom)

This is the goal: replace the ReactDOM object with one of our own and keeping the Counter APP running.

import React from 'react';
-import ReactDOM from 'react-dom';
+import ReactDOM from './my-custom-react-dom';
import './styles.css';
Enter fullscreen mode Exit fullscreen mode

✨ Ah! and that's also deployed at Vercel: https://my-react-hvpqtmgva-manu-artero.vercel.app/

Screenshot for https://my-react-hvpqtmgva-manu-artero.vercel.app/

If you open de dev tools, you may check the console:

Screenshot of the console


At this point, I took a small leap: while implementing a tiny react-dom is one thing, crafting the plugin for the terminal is a different tale.

So i introduced the solution by Vadim Demedes: Ink.

Ink is a React renderer for the terminal.

I did prepare a playground (check the playground branch) with just 2 dependencies: ink and react

You can check the final code at GitHub. Anyway, in a nutshell:

...

function useWorld({ onGameOver, onGameWin }) {
  const [world, setWorld] = useState([
    "tree",
    "character",
    "tree",
    "tree",
    "tree",
    "enemy",
  ]);

  useEffect(() => {
     ...
      if (random > 0.5) {
        return moveEnemyRight();
      }
      if (random < 0.5) {
        return moveEnemyLeft();
      }
    }
  });

  const moveEnemyRight = () => {
    setWorld((currentWorld) => {
      ... bla bla
    });
  };

  const moveEnemyLeft = () => {
    setWorld((currentWorld) => {
      ... bla bla
    });
  };

  const moveCharacterRight = () => ...

  const moveCharacterLeft = () => ...

  return { world, moveCharacterRight, moveCharacterLeft };
}


function App() {
  const { exit } = useApp();
  const { world, moveCharacterRight, moveCharacterLeft } = useWorld({...});

  useInput((input, key) => {
    if (input === "q") {
      exit();
    }
    if (key.leftArrow) {
      setDisplayText("<-");
      return moveCharacterLeft();
    }
    if (key.rightArrow) {
      setDisplayText("->");
      return moveCharacterRight();
    }
  });

  return (
    <>
      <Ground>
        {world.map((type, i) => (
          <WorldElement key={`${type}-${i}`} type={type} />
        ))}
      </Ground>
      <Text>{displayText}</Text>
    </>
  );
}

...

render(<App />);
Enter fullscreen mode Exit fullscreen mode

Resulting in this little fella:


Honestly, it was a tremendous success; many people congratulated me.


thanks for reading πŸ’›.

Top comments (2)

Collapse
 
proteusiq profile image
Prayson Wilfred Daniel

That is awesome. I would not have completed a sentence React in... with word terminal. This is 🀯

Collapse
 
michthebrandofficial profile image
michTheBrandofficial

How the hell can you render that? And what the hell is going on? πŸ˜‚