GitHub

Core Concepts

Components and Islands

Components are reusable parts of your application UI. In Radonis, components are rendered server-side by default, but can be upgraded to islands that are also hydrated client-side for interactivity.


Usage

Create your components somewhere in the resources directory, preferably in resources/components. Components that should be hydrated client-side must be wrapped with the island function and placed in files ending with .island.<ext>.

// resources/components/SomeInteractiveIsland.island.tsx
import { island } from '@microeinhundert/radonis'


function SomeInteractiveIsland({ message }: { message: string }) {
  function handleClick() {
    alert(message)
  }


  return <button type="button" onClick={handleClick}>Click me</button>
}


// The first argument should be a unique name for the island
export default island('SomeInteractiveIsland', SomeInteractiveIsland)

Note

Make sure islands don't import server-only code.

Hydrating islands

In Radonis, islands are not hydrated automatically. In order for Radonis to hydrate an island, wrap it with the HydrationRoot component.

// resources/views/YourView.tsx
import { HydrationRoot } from '@microeinhundert/radonis'
import SomeInteractiveIsland from '../components/SomeInteractiveIsland.island.tsx'


function YourView() {
  return (
    <HydrationRoot>
      {/* This island will be hydrated client-side */}
      <SomeInteractiveIsland message="Hello world" />
    </HydrationRoot>
  )
}

Note

Omitting the HydrationRoot will just render the component on the server only.

Working with HydrationRoots

  • HydrationRoots can only hydrate valid islands.
  • HydrationRoots don't accept a component with children as direct child.
  • Hydration will only take place once the HydrationRoot is in view.
  • HydrationRoots only accept a single component as direct child.

Example of correct usage

<HydrationRoot>
  <YourIsland />
</HydrationRoot>

Examples of incorrect usage

// Must be the direct child
<HydrationRoot>
  <Suspense>
    <YourIsland />
  </Suspense>
</HydrationRoot>


// Can't have multiple direct children
<HydrationRoot>
  <YourIsland />
  <AnotherComponent />
</HydrationRoot>


// The direct child can't have children of its own
<HydrationRoot>
  <YourIsland>
    <AnotherComponent />
  </YourIsland>
</HydrationRoot>

Hydration and Lucid

By default, data returned from your Lucid models after serialization is snake_cased. In order for data to be of the same format on both the client and the server, a custom naming strategy should be used. This naming stategy makes sure properties are kept camelCased after serialization. The following snippet shows a custom naming strategy that achieves this.

// app/Strategies/CamelCaseNamingStrategy.ts
import { string } from '@ioc:Adonis/Core/Helpers'
import { SnakeCaseNamingStrategy, BaseModel } from '@ioc:Adonis/Lucid/Orm'


export default class CamelCaseNamingStrategy extends SnakeCaseNamingStrategy {
  public serializedName(_model: typeof BaseModel, propertyName: string) {
    return string.camelCase(propertyName)
  }
}

To use the custom naming strategy for your models, add it to each model class on the static namingStrategy property.

// app/Models/YourModel.ts
import CamelCaseNamingStrategy from 'App/Strategies/CamelCaseNamingStrategy'
import { BaseModel } from '@ioc:Adonis/Lucid/Orm'


export default class YourModel extends BaseModel {
  public static namingStrategy = new CamelCaseNamingStrategy()
}
Previous
Views