Home > Web Front-end > JS Tutorial > body text

Build a Tiny React ChSX

Mary-Kate Olsen
Release: 2024-10-20 18:29:30
Original
211 people have browsed it

Build a Tiny React ChSX

This series will build a tiny frontend framework, functionally similar to React, to illustrate how React works under the hood. This chapter covers JSX.

I will use Bun as runtime. Node may need extra configuration for typescript and compiling.

This tutorial is based on this tutorial, but with JSX, typescript and an easier approach to implement. You can checkout the notes and code on my GitHub repo.

JSX

Now, before we go any deeper, let's look at several important element of react- jsx first.

If you ever took a look at the transpiled code of a React component, you will see that it is just a bunch of function calls. JSX is just a syntactic sugar for React.createElement. That is, for exmaple, the following JSX code:

const element = <h1 className="greeting">Hello, world!</h1>;
Copy after login
Copy after login

Will be transpiled to:

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
Copy after login
Copy after login

React.createElement will create a virtual element, which is another core mechanism. To put it simply, virtual element is the element in virtual DOM. A virtual DOM is something that represents the actual DOM. Since operating on virtual DOM is simply operating js objects, it is much faster than operating on actual DOM. We will talk about virtual DOM in the next chapter. But for now, knowing that JSX is just a syntax sugar for React.createElement is enough.

The React.createElement function takes the following arguments in order,

  1. The tag name of the element. Some tags are special, like div, span, h1, etc. These are called intrinsic elements. Some tags are user-defined components.
  2. The props of the element. This is an object that contains the properties of the element. For example, the className of the h1 element above is greeting.
  3. The children of the element. This can be string or element. Please note that this parameter is represented as ...children in the function signature, which means that it can take any number of arguments.

It sounds an easy job, right? So let's do it.

Implement JSX

When it comes to compilation, we can specify the function to use- by default, the function is React.createElement. But we can use our own function.

So we create a v-dom.ts, so as to define the virtual element first.

export type VDomAttributes = { 
    key?: string | number
    [_: string]: string | number | boolean | Function | undefined
}

export interface VDomElement {
  kind: 'element'
  tag: string
  children?: VDomNode[]
  props?: VDomAttributes
  key: string | number | undefined
}

export type VDomNode = 
| string
| VDomElement
Copy after login
Copy after login

Please note that we have a key field in each node (node is just a name for either text or element). This is for reconciliation, which we will talk about in the next chapter. You can safely ignore it for now.

Now we can implement the createElement function. We put it in the same file.

export function createElement(tag: string, props: VDomAttributes, ...children: VDomNode[]): VDomElement {
  console.log('createElement', tag, props, children)
    return {
        kind: 'element',
        tag,
        children,
        props,
        key: props?.key ?? undefined
    }
}
Copy after login
Copy after login

Now we instruct our compiler to use this function. We can do this by adding the following line to the top of our file.

const element = <h1 className="greeting">Hello, world!</h1>;
Copy after login
Copy after login

Please note that since we are adopting react standard, we need to introduce the React type definition. We can do this by adding the following line to the top of our file.

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
Copy after login
Copy after login

Then in the tsconfig.json, we add the following line to the compilerOptions field.

export type VDomAttributes = { 
    key?: string | number
    [_: string]: string | number | boolean | Function | undefined
}

export interface VDomElement {
  kind: 'element'
  tag: string
  children?: VDomNode[]
  props?: VDomAttributes
  key: string | number | undefined
}

export type VDomNode = 
| string
| VDomElement
Copy after login
Copy after login

Now, we can take a look at the virtual element we created.

export function createElement(tag: string, props: VDomAttributes, ...children: VDomNode[]): VDomElement {
  console.log('createElement', tag, props, children)
    return {
        kind: 'element',
        tag,
        children,
        props,
        key: props?.key ?? undefined
    }
}
Copy after login
Copy after login

You will see just our defined virtual dom element based on the JSX code.

Furthermore, we can also define a fragment element- the <>, if you don't know its official name. We can do this by adding the following line to the top of our file.

When dealing with fragment, the compiler will take the configured fragment factory to the tag in the element creation function. This is the same as how functional components work- functional component will take the function to the tag, which we will demonstrate in the next chapter.

Nonetheless, in our implementation, there is no need for complex handling- we just need to set a special tag for fragment.

import { createElement as h } from './v-dom'
Copy after login

Extra compiler options,

bun i @types/react
Copy after login

Basically, fragment is just a special element with an empty tag. When it comes to the creation of fragment, the compiler will fetch the jsxFragmentFactory and put it into the tag parameter in the first parameter of createElement. So we can easily distinguish fragment from other elements.

"compilerOptions": {
    "jsx": "react",
    "jsxFactory": "createElement",
}
Copy after login

This code will correct yield the virtual DOM. So far, we have implemented the JSX part of our tiny react.

Footnote

Ugh, this is the author from chapter three. Actually, the current implementation of JSX is not perfect. We will fix it in the third chapter. Now it does not support syntax like,

import { createElement } from "./v-dom";

function App() {
    return <div>
        <h1>a</h1>
        <h2>b</h2>
    </div>
}

console.log(App());
Copy after login

This is because every {} is treated as one child, where as the map returns an array. So it will have nested children.

Also we hadn't supported functional components yet, which is in the next chapter.

You can just follow the current one and fix it later. Sorry for the inconvenience.

The above is the detailed content of Build a Tiny React ChSX. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!