2

So the situation - I want to create application\framework that would utilize React and user\3rd party built components (Widgets). My current view is that I'll have a Root component that will list loaded 3rd party components. Like so:

class Root {
 constructor(p){
  this.state = {loadedWidgets: [<Chat/>, <Mail/>, <Notes/>]}
 }
 render(){
  return(
   <div>
    <Header/>
    <Body>
     {this.state.loadedWidgets.map(WidgetName => <WidgetName />)}
    </Body>
   </div>
  )
 }
}

But I encountered two major problems that I can't understand or find how to solve:

  1. How would I load (import) those widgets if I shouldn't hard code them into Root component? (I suppose I could make some hooks so that after user install widgets it'll be added to state and page somehow)
  2. Why React doesn't render real components that way:

(List end for code tag to work properly)

 render(){
  const NameOfACustomComponent = this.state.loadedWidgets[0]
  return(<div><NameOfACustomComponent/></div>
 }

After rendering it'll be a custom DOM tag and not existing React Component.

What I want is to build is an extension for chrome to substitute new page with small widgets\apps that user frequently uses and at the same time leave for developers possibility to add new widgets in simple enough manner with pure React.js and some hooks for integration.

EDIT. Found answer to a 2nd question, according to this issue React allow to make arbitrary components if you have reference to its class or function (ES5 React style). So one of the solutions to both 2 and 1 questions is to have some registry in window object where any component could just add itself up and be available to the framework. Though it should be done in strict Class instance manner to provide a method to add\remove only Widget itself and not an entire list of them.

1
  • Is the third party components are made of React? Commented Nov 9, 2016 at 10:04

2 Answers 2

1

You're almost there, change

{this.state.loadedWidgets.map(WidgetName => <WidgetName />)}

to

{this.state.loadedWidgets.map(Widget => Widget)}

or probably should work also:

{this.state.loadedWidgets}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, after reading issue mentioned in the edit I understand that I would have to have references to all components, but first I thought about some magical way for React to know all of its components by their names. Now I understand that it can only operate knowing components that it should use.
1

Sorry, I couldn't post full-fledged solution earlier.

The main problem with dynamic component loading is firstly the way to alert the main renderer component that some DC (dynamic component) was added or removed. The second one is smaller and could be easily fixed by solving first one via an object that would handle components manipulation and thus any DC could just add itself and this object (RDCL) will alert any subscribers about that. Sample RDCL could look like that:

class RDCL extends Array { //so we could use filtering and stuff
  subscribe(componentType, callback) { // handle the way to notify subscriber when C. with corerct type added to RDCL }
  unsubscribe(componentType = ALL, callback) { // remove subscription }
  add(componentClassOrFunctionDefinition, [typeGoesHere?]) { // add component with default or provided or included type }
  remove(componentClassOrFunctionDefinition) { // remove component }
}

Though with dynamic third party components arise another problem - how to handle bundling without including react and all libraries that already included in main app\framework. For this one, I still don't have answer, other than using plain scripts with type/babel in them

In case where you don't need third party components but want to load them dynamically anywhere across your app there's simple (and probably very dirty) solution:

window.ReactComponentRegistry = {}; // somewhere in root component

// some component that should be loaded dynamicaly (somewhat)
class SomeComponent exteds Component { // ... };
window.ReactComponentRegistry['SomeComponentName'] = SomeComponent;

//render() of view that would use that dynamic component
const ArbitraryComponent = window.ReactComponentRegistry.SomeComponentName // ['SomeComponentName'] obviously will work too
return(<ArbitraryComponent props={this.props} />);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.