Working with functional components

It’s possible to use custom React components in Plasmic Studio via app-hosting. You can learn more about app-hosting and code components.

Plasmic Studio uses React refs by default to interact with custom code components in the editor.

However, some components don’t accept refs—for example functional components that don’t use ref forwarding.

You can still work with these in Plasmic Studio by either:

  • Running a code snippet before React is imported (recommended)—options 1a and 1b below.
  • Wrapping them in components that expose refs—option 2 below.

Option 1a: Add a preamble script to the host page’s header

You can add a <script/> that contains a small piece of @plasmicapp/host:

Copy
<script>
!function(){const n=window,i="__REACT_DEVTOOLS_GLOBAL_HOOK__",o="__PlasmicPreambleVersion",t=function(){}
if(void 0!==n){if(n.parent!==n)try{n[i]=n.parent[i]}catch(e){}if(!n[i]){const r=new Map
n[i]={supportsFiber:!0,renderers:r,inject:function(n){r.set(r.size+1,n)},onCommitFiberRoot:t,onCommitFiberUnmount:t}}n[i][o]||(n[i][o]="1")}}()
</script>

We do not anticipate needing you to update this snippet, but as an alternative, you can dynamically load the current version of this script (at the cost of some load performance, as this is a blocking script load—but if you use an SSG and can limit the load to just the host page, then you should be fine):

Copy
<script src="https://static1.plasmic.app/preamble.js" />

Since it needs to run before React, the most sure-fire place to add this is the start of <head/>. For example, if you’re using Create-React-App, it should go into public/index.html. For Next, you can use the Head component in next/head to add the script to the host page. For Gatsby you can inject the script tag through gatsby-ssr.js.

Option 1b: Ensure @plasmicapp/host is imported before React loads

@plasmicapp/host contains the same snippet as above, so if you are able to ensure @plasmicapp/host is imported before React is run for the first time, then you can alternatively just make this import.

This would work with create-react-app—the JavaScript entry point is src/index.js, so you would just need to make sure that @plasmicapp/host is the first import:

Copy
// tslint:disable:ordered-imports
// organize-imports-ignore
import '@plasmicapp/host';
import * as React from 'react';
// ...

This doesn’t work for stacks like Next.js and Gatsby, since React is always run before the framework gets to your code.

Option 2: Register a wrapped version of the component

Lastly, you can simply wrap any component in a class component (or a functional component that has a ref-forwarded div) when registering to Plasmic, even if you don’t want to use the wrapper in your codebase. For example, if you have the following functional component:

path/to/MyFunctionComponent.tsx
Copy
import * as React from 'react';
export interface MyFunctionComponentProps {
className: string;
}
export function MyFunctionComponent({ className }: MyFunctionComponentProps) {
return <div className={className}>Hello, world!</div>;
}

Then you can register it the following way:

Copy
import { MyFunctionComponent, MyFunctionComponentProps } from 'path/to/MyFunctionComponent';
class MyFunctionComponentWrapper extends React.Component<MyFunctionComponentProps> {
render() {
return <MyFunctionComponent {...this.props} />;
}
}
registerComponent(MyFunctionComponentWrapper, {
name: 'MyFunctionComponent',
props: {
className: 'string'
},
importPath: 'path/to/MyFunctionComponent'
});

The cons of this method are: (1) unlike the others, it requires special setup for each functional component; and (2) it might break a parent component if it type-checks the children (for instance, a Menu that requires its children to be MenuItems).

Give feedback on this page