How to access data from Builder in a React Custom Component

Often times you will want to access state data from Builder inside your custom components, either to bind a state value to some part your component, or to affect the rendering of your custom component based on state inputs.

There are a number of ways you can do this within Builder, many using native features of React itself. Below, we have outlined a number of ways:

1. Using React Context
React provides Context to share global variables without having to pass props between parent and child.

Using a Context provider to wrap your <BuilderComponent /> will thus make any values shared in the Context available to children of your <BuilderComponent />, such as your custom component. This is particularly useful if there are values that are global or shared across state within your app.

To set this up you could do something like:

<Context.Provider value={{ foo: 'bar' }}>
   <BuilderComponent model="YOUR_MODEL" />
</Context.Provider>

Now, within your custom code, you will have access to the foo value above:

export const MyCustomComponent = props => {
    const { foo } = useContext(Context)
    return (
       <h1>{props.header}</h1>
       <div>{foo}</div>
    )
}

Builder.registerComponent(BuilderTextField, {
    name: 'MyCustomComponent',
  inputs: [{ name: 'header', type: 'string' }]
})

2. Using BuilderStoreContext
Within the Builder Visual Editor, we use React Context to share global values, such as state, across components. If you want to access this Builder-provided context instead of your own within your app, you can simply access using:

export const MyCustomComponent = props => {
    const builderContext = useContext(BuilderStoreContext)
    return (
       <h1>{props.header}</h1>
       <div>{builderContext.state.someStateValue}</div>
    )
}

3. Accessing builderState prop
Finally, within the props passed to your custom component, you will find a builderState prop that has access to state values. You can access this directly within the component itself:

export const MyCustomComponent = props => {
    return (
       <h1>{props.header}</h1>
       <div>{props.builderState.state.someStateValue}</div>
    )
}

4. Using a Default Binding
When creating your custom component, you can set a default value for an input to come from a value within state. This is particularly useful if you know a component will be used within a content entry that always expects some sort of value in state. For example, if you have a custom Product Box component that always expects a product in state.

Within your app, you could pass that product into state using the data prop:

<BuilderComponent model="product-page-bottom" data={ { product: currentProduct }} />

And then set the binding in the custom component:

Builder.registerComponent(ProductBox, {
    name: 'ContextAwareProductBox',
    description: 'should only be used n product page template, dynamically bind to product in context.',
    inputs: [ ... ],
    defaults: {
      bindings: {
        'component.options.product': 'state.product',
      },
    },
)
4 Likes

UPDATE:
If you are using a Gen2 SDK then #3 listed above won’t work for you. Instead you would want to use props.builderContext.rootState

5. Accessing rootState from builderContext prop in Gen2 SDK
Finally, within the props passed to your custom component, you will find a builderContext prop that has access to the rootState which contains state values. You can access this directly within the component itself:

export const MyCustomComponent = props => {
    return (
       <h1>{props.header}</h1>
       <div>{props.builderContext.rootState.someStateValue}</div>
    )
}