ChatiumFor developersPlaygroundPricing
Sign in

Isomorphic Pages and Components

In web development, there is a concept of isomorphism, which means that the same code can run both on the server and on the client side in the browser. This allows developers to create applications that work equally efficiently in both environments using the same technologies and development tools.

The advantage of isomorphism is that developers do not need to write separate code for the server-side and client-side parts of the application. They can use the same code that adapts to the execution environment.

Components that will be used in the browser (isomorphic components) should be marked in the file with a comment on the first line: // @shared.

If a component is marked this way, its code can be sent to the browser. If there is no mark, the code is not sent to the browser.

// @shared

export function MyComponent(props: MyComponentProps) {
  const ref = nanoid() // component identifier

  return (
    <div>
      <MyComponentInitializer
        ctx={ctx} // context
        ref={ref} // identifier

        title={'one'} // component properties
        subTitle={'two'}
      />
    </div>
  )
}

export const MyComponentInitializer = createClientInitializer(async ({ ctx, element, ...props }) => {
  // element = <div>
  // props.title
  // props.subtitle

  console.log('This code will only run on the client')
})

In one file, both the body of the component that will run on the server and the client initialization code are defined.

Since components have a special initializer (createClientInitializer), special initialization is required for their correct operation when dynamically adding or removing them on the client. For this, there are methods similar to DOM methods for inserting tree elements, which allow components to initialize correctly.

Auxiliary Attributes style and script

For style and script tags, additional attributes portal and portalDedupe can be used.

portal can take values: body-start, body-end, head-start, head-end. It indicates which tag to move the loading of the script or styles to.

portalDedupe means that if such a script or style has already been added, it does not need to be added again.

Example usage:

<link
  href="/my-component.css"
  rel="stylesheet"
  portal="head-end"
  portalDedupe
/>

Client-Side Methods

appendChild

The component is added as a child as the last element. This is used when creating a new element on the client.

await appendChild(
  element,
  <MyComponent
    ctx={ctx}
    title={'Second Title'}
    subTitle={'Second Subtitle'}
  />
)

insertBefore

The component is added as a child before the specified element. This is used when creating a new element on the client and displaying it in a specific place among siblings.

await insertBefore(
  element,
  <MyComponent
    ctx={ctx}
    title={'Will be First'}
    subTitle={'Subtitle'}
  />,
  firstElement
)

replaceWith

The component replaces an element. It can be used when changing a component or for re-rendering the entire component.

let componentElement = await replaceWith(
  componentElement,
  <MyComponent
    ctx={ctx}
    title={'Updated Title'}
    subTitle={'Updated Subtitle'}
  />
)

toHtmlElement

There is a helper function that prepares the component and returns it as a DOM element for further actions using the standard browser SDK.

It takes document as the first argument.

const myComponentElement = await toHtmlElement(
  document,
  <MyComponent
    ctx={ctx}
    title={'Updated Title'}
    subTitle={'Updated Subtitle'}
  />
)

document.body.appendChild(myComponentElement)