Migration guide v3 > v4
Relationship fields
The value returned from a relationship field (as a prop on the brick for a sideEditProp
or on the customValues
for a customField
) now contains only the ID of the related entity.
If you need to get also the complete object for the related entity, you need to specify embedEntity: true
in the relationshipOptions
.
Example with sidebar control
import { types } from 'react-bricks/frontend'
MyComponent.schema = {
...
sideEditProps: [
{
name: 'categoryId',
type: types.SideEditPropType.Relationship,
label: 'Product Category'
relationshipOptions: {
references: 'category'
multiple: false
embedValues: true
}
}
]
}
Example with pageType-level custom field
import { types } from 'react-bricks/frontend'
const pageTypes: types.IPageType[] = [
{
name: 'product',
pluralName: 'products',
defaultLocked: false,
defaultStatus: types.PageStatus.Published,
getDefaultContent: () => [],
customFields: [
{
name: 'categoryId',
type: types.SideEditPropType.Relationship,
label: 'Product Category'
relationshipOptions: {
references: 'category'
multiple: false
embedValues: true
}
},
],
},
...
]
React Server Components
Since v4.2, React Bricks supports React Server Components (RSC), in the Next.js starters with App Router.
When using Server Components, the visual components (Text, RichText, Image, File Repeater, Link) must be imported from react-bricks/rsc
and they have a slightly different APIs, as we need to pass them the value of the prop.
1. Text
Add the value
prop. You get it from the component's props.
The type should be declared as ReactBricks.types.TextValue
.
Before
import { Text } from 'react-bricks/frontend'
...
<Text
propName="title"
placeholder="Enter the title"
renderBlock={({ children}) => (
<p className="text-xl">
{children}
</p>
)}
>
After
import { Text } from 'react-bricks/rsc'
...
<Text
propName="title"
value={title}
placeholder="Enter the title"
renderBlock={({ children}) => (
<p className="text-xl">
{children}
</p>
)}
>
2. RichText
Add the value
prop. You get it from the component's props.
The type should be declared as ReactBricks.types.TextValue
.
Before
import { RichText } from 'react-bricks/frontend'
...
<RichText
propName="title"
placeholder="Enter the title"
renderBlock={({ children}) => (
<h1 className="text-xl">
{children}
</h1>
)}
>
After
import { RichText } from 'react-bricks/rsc'
...
<RichText
propName="description"
value={description}
placeholder="Enter the description"
renderBlock={({ children}) => (
<p>
{children}
</p>
)}
allowedFeatures={[types.RichTextFeatures.Bold]},
>
3. Image
Add the source
prop. You get it from the component's props.
The type should be declared as ReactBricks.types.IImageSource
.
Before
import { Image } from 'react-bricks/frontend'
...
<Image propName="avatar" alt="Avatar" />
After
import { Image } from 'react-bricks/rsc'
...
<Image
propName="avatar"
source={avatar}
alt="Avatar"
/>
4. File
Add the source
prop. You get it from the component's props.
The type should be declared as ReactBricks.types.IFileSource
.
Before
import { File } from 'react-bricks/frontend'
...
<File propName="document" />
After
import { File } from 'react-bricks/rsc'
...
<File
propName="document"
source={document}
/>
5. Repeater
Add the items
prop. You get it from the component's props.
The type should be declared as ReactBricks.types.RepeaterItems
.
Before
import { Repeater } from 'react-bricks/frontend'
...
<Repeater propName="features" />
After
import { Repeater } from 'react-bricks/rsc'
...
<Repeater
propName="features"
items={features}
/>
6. Client Bricks
For interactive bricks, which need client hydration, you need to create 2 components: a server wrapper and the client component, in this way:
import { types, wrapClientComponent } from 'react-bricks/rsc'
import { RegisterComponent } from 'react-bricks/rsc/client'
import MapClient, { MapProps } from './MapClient'
const MAPTILER_ACCESS_TOKEN = '' // Insert access token
const schema: types.IBlockType<MapProps> = {
name: 'map',
label: 'Map',
category: 'contact',
tags: ['contacts', 'map'],
playgroundLinkLabel: 'View source code on Github',
playgroundLinkUrl:
'https://github.com/ReactBricks/react-bricks-ui/blob/master/src/website/Map/Map.tsx',
previewImageUrl: `/bricks-preview-images/map.png`,
getDefaultProps: () => ({
lat: '45.6782509',
lng: '9.5669407',
zoom: '6',
}),
sideEditProps: [
{
name: 'zoom',
label: 'Zoom',
type: types.SideEditPropType.Number,
},
{
name: 'lat',
label: 'Latitude',
type: types.SideEditPropType.Number,
},
{
name: 'lng',
label: 'Longitude',
type: types.SideEditPropType.Number,
},
{
name: 'maptiler',
label: 'MapTiler',
type: types.SideEditPropType.Custom,
show: () => !MAPTILER_ACCESS_TOKEN,
component: () => {
if (!MAPTILER_ACCESS_TOKEN) {
return (
<p className="text-sm">
For better maps, please create a MapTiler free account and set the{' '}
<code className="text-xs">MAPTILER_ACCESS_TOKEN</code> string.
</p>
)
}
return null
},
},
],
}
export default wrapClientComponent({
ClientComponent: MapClient,
RegisterComponent,
schema,
})
'use client'
import { Map, Marker } from 'pigeon-maps'
import { maptiler } from 'pigeon-maps/providers'
import React from 'react'
export interface MapProps {
zoom: string
lat: string
lng: string
mapTilerAccessToken: string
}
export const MapClient: React.FC<MapProps> = ({
lat = '45.6782509',
lng = '9.5669407',
zoom = '10',
mapTilerAccessToken,
}) => {
const mapTilerProvider = React.useCallback(
(x: number, y: number, z: number, dpr?: number | undefined) =>
maptiler(mapTilerAccessToken, 'streets')(x, y, z, dpr),
[mapTilerAccessToken]
)
let mapTilerProviderProp = {}
if (mapTilerAccessToken) {
mapTilerProviderProp = {
provider: mapTilerProvider,
}
}
return (
<Map
center={[parseFloat(lat), parseFloat(lng)]}
height={350}
metaWheelZoom
zoom={parseInt(zoom, 10)}
{...mapTilerProviderProp}
dprs={[1, 2]}
metaWheelZoomWarning="Use ctrl + wheel to zoom!"
attribution={false}
>
<Marker anchor={[parseFloat(lat), parseFloat(lng)]} />
</Map>
)
}
export default MapClient
7. Fetching data from a brick
We can directly fetch external data from a brick, without having to create the getExternalData
on a pageType
.
In a brick, we can just add to the schema
a getExternalData
function, which should be an async function, returning a promise that resolves to an object. This object will be merged to the component's props.
See the new External Content documentation.