renchap/webpacker-react

cant render a component that has not been registered with multiple calls to WepbackerReact.setup

Closed this issue · 2 comments

I have an application with several components, some of which are needed only in certain views, so I split them in multiple packs and I load them using the content_for helper. For example, I have two packs:

//clients.js loaded in clients#index
import ClientsRoot from '../src/clients';
import WebpackerReact from 'webpacker-react';

WebpackerReact.setup({ ClientsRoot });

//sales_agents.js loaded in sales_agents#index
import SalesAgentsRoot from '../src/sales_agents';
import WebpackerReact from 'webpacker-react';

WebpackerReact.setup({ SalesAgentsRoot });

Everything seems to work fine but I noticed that when I switch from one view to the other the console prints an error: webpacker-react: cant render a component that has not been registered.

I'm wondering if this is the correct way to add new components to an already setup WebpackerReact or if this is something that shouldn't be done at all.

I recently hit this issue. The problem is that setup will subsequently call mountComponents which scans the DOM and tries to mount everything. I solved it by creating an application.js pack that looks like this:

import ujs from 'webpacker-react/ujs'
import WebpackerReact from 'webpacker-react/hmr'

// This sets up React components to render when they are able. The default
// setup method will try and mount components immediately which doesn't
// work with our pack setup
if (typeof window.WebpackerReact === 'undefined') {
  window.WebpackerReact = WebpackerReact
}
ujs.setup(() => { WebpackerReact.mountComponents() }, () => { WebpackerReact.unmountComponents() })

and then in various pack files, call registerComponents instead of setup. So in your case:

//clients.js loaded in clients#index
import ClientsRoot from '../src/clients';
import WebpackerReact from 'webpacker-react';

WebpackerReact.registerComponents({ ClientsRoot });

//sales_agents.js loaded in sales_agents#index
import SalesAgentsRoot from '../src/sales_agents';
import WebpackerReact from 'webpacker-react';

WebpackerReact.registerComponents({ SalesAgentsRoot });

If you don't want to include an extra pack file (it worked for us as we have some global components), you could always create your own setup function and import that instead.

This works but it still requires me to include all the packs in all my pages. What I am trying to do is to load the script that registers the new components on demand only when the user opens a certain page.

I found this issue in the turbolinks repository that says that what I am trying to do is not possible because scripts are loaded asynchronously and thus the official recommendation is to put all the scripts together in all the pages (i.e. in the layout).