Rendering a string as React component - reactjs

I want to render the react components with a string as the input which i am receiving dynamically from another page. BUt i will have the references for the react components.
Here is the example
Page1:
-----------------------------
loadPage('<div><Header value=signin></Header></div>');
Page2:
--------------------------------
var React =require('react');
var Header = require('./header');
var home = React.createClass({
loadPage:function(str){
this.setState({
content : str
});
},
render : function(){
return {this.state.content}
}
});
In this example i am receiving Header component as string , and i have the reference of Header component in my receiving page . How can i substitute the string with the actual react component

This react-jsx-parser component looks like it will solve your problem

To render a react component using a string you can use.
var MyComponent = Components[type + "Component"];
return <MyComponent />;
For more information check the response here :
React / JSX Dynamic Component Name

If you can live with having all your components in one module, then this works pretty well:
import * as widgets from 'widgets';
var Type = widgets[this.props.componentId];
...
<Type />
The wildcard import works like a cut-rate component registry.

Built-in way
Without any package You can use the built in react attribute dangerouslySetInnerHTML to pass your string, and it will render it as an HTML
function Component() {
const stringElement = "<h1> My Title </h1>";
return (
<div dangerouslySetInnerHTML={{ __html: stringElement }}>
</div>
);
}
And it would work fine.
But try to avoid rendering text as much as possible, since it might expose you to XSS attacks, you should XSS clean the text or avoid this unless you have no choice

one more way to use component
const a = {
b: {
icon: <component props />
}
}
In render function
return(
{a.b.icon}
)
This will render your component in your JSON object

This string-to-react-component library can help you to achieve your desired functionality

Related

How to create and use a component from a jsx string loaded from database in reactjs

I am trying to build a system in nextjs where user can add their own react components with variables, functions, logics and I would like to store them in a database and then load those string component in my next application so they work at run time. Here is an example of what I am trying to do
const Home: NextPage = () => {
const Test = `export default function Test() {
return (
<div>
<h1>Testing component loading....</h1>
</div>
)
}`
return (
<>
<Test/>
<h1> this is a nice h1 tag</h1>
</>
)
}
export default Home
Here, Test is the an example component can assume coming from an api call. How can I load the logic and everything to work in my next application?
I have react jsx parser and other things, I was able to make jsx works, but didn't get success in making js code works or logics.
I want to add the power of react in the component as well not just jsx only.
Thank you.
Idea is
String from DB
=> server create JSX file from string
=> put JSX file into development env
=> create Route to that JSX file => server proxied to that Route

How to render component's child instead of entire component

I have the react-bnb-gallery package with single default exported component named ReactBnbGallery. It shows the gallery through the portal and works well but my goal is to get that gallery inline in html and nested in components tree.
Currently what I have:
<SomeWrapperComponent>
<ReactBnbGallery /> // contains not accessible <Gallery/>
<SomeWrapperComponent />
and I want this:
<SomeWrapperComponent>
<Gallery/>
<SomeWrapperComponent />
In this way I want to omit the portal and have the gallery right inside my layout.
Any suggestions???
I thought about some HOC over the <ReactBnbGallery>
or maybe Portals have some api or another switcher to simply turning off
Thanx in advance !
The Gallery component is now accessible outside the portal.
This is now possible using the following code:
import { Gallery } from 'react-bnb-gallery';
const MyComponent = () => (
<Gallery photos={[...]} />
);
If you want to use also the main ReactBnbGallery component, the new way is doing the following:
import { ReactBnbGallery } from 'react-bnb-gallery';
const MyComponent = () => (
{ /* ReactBnbGallery wraps the Gallery component */ }
<ReactBnbGallery photos={[...]} />
);
The updates have been published in NPM with the new version 1.1.7.

Trying to render a new instance in ReactJS

As an example (real tried code)
I have a component of which I want to initiate a NEW instance for rendering.
import React, { Component } from 'react';
export default class TinyObject extends Component {
constructor(props) {
super(props);
console.log("TinyObject constructor");
}
render() {
console.log("TinyObject render");
return (
<div>HEY THIS IS MY TINY OBJECT</div>
);
}
}
Then in main App constructor I do the following:
var myTinyObject = new TinyObject();
var myArray = [];
myArray.push(myTinyObject);
this.state = {testing: myArray};
Then a created a function to render this:
renderTest()
{
const {testing} = this.state;
const result = testing.map((test, i) => {
console.log(test);
return {test};
});
}
And I call this from the App render function like this:
render() {
const { gametables, tableActive } = this.state;
console.log("render");
return <div><div>{this.renderTest()}</div></div>;
}
It runs, no errors.
I see console log of the following:
console.log("TinyObject constructor");
console.log(test);
But I don't see console log of the TinyObject render nor do I see the render output.
Thanks to lustoykov answer I got a little further
JSX: var myTinyObject = <TinyObject />;
works!
but in the real app I add a little more and don't know how to do it here.
return <GameTable key={'gt'+index} data={table} settings={this.settingsData} sendTableNetworkMessage={this.sendTableNetworkMessage} />
this is the way I was rendering; and I needed more instances of GameTable
now the question is; how do I add the arguments like data & settings to myTinyObject.
thanks for helping so far.
You don't manually instantiate react component, use JSX or createElement. For instance
via JSX
var myTinyObject = <TinyObject prop1={prop1} prop2={prop2} />;
via React.createElement
var myTinyObject = React.createElement(TinyObject, { prop1, prop2 }, null);
I would definitely check out some tutorials and how React works at a basic level. You aren't really going to call your react components like you would normally do in javascript since the render function returns jsx.
Fundamentally, React is what is called a single page application. That means that your browser will load up a single html file with a div. Now that div will be where React performs its magic by using Javascript to change stuff around.
It is easiest for me to think of React as a tree. You create these components that you place on the DOM or in your HTML and React will add and remove them downwards. For instance, take a look at this picture of twitter.
So first the Feed component is going to be put on the DOM. Then the Feed component will render the Tweet components. So as you can see the rendering goes in one direction, downwards.
Now, as you can see your render methods are not returning javascript. It is returning something that looks like HTML but we call it JSX. That means we want to render it a little differently with our react classes.
If we have a child component:
class Child extends React.Component {
render() {
return <h1>Hello, I am inside the parent component</h1>;
}
}
We can call the render method like this:
class Parent extends React.Component {
render() {
<Child /> //This is how I use the Child class
}
}
Now the reason why react is so performant is that the child cannot be re-rendered unless we do 1 of two things:
It is a component with a state and we call a method setState()
We pass down new props to a child component from the parent component
You can read about it here
Now the only way to get React to call that render function again is by doing those two things.

Access to internal function from externally loaded HTML in React component

I have the following use case.
Some HTML from a third party source is loaded inside my React component:
class MyComponent extends Component {
render() {
return (
<div
dangerouslySetInnerHTML={{ __html: this.props.externalHTML }}
/>
);
}
}
Inside the externally loaded HTML a click event exists for a specific span, which is supposed to call a callback function that exists in my application.
<span onclick="myCallback(param1='asd', param2=123, param3='asdas')">
Click me!
</span>
Where should I put this myCallback function?
If I place it inside the component class I get the following error when clicking the span, because as I understand the function is not visible to the externally loaded HTML: Uncaught ReferenceError: myCallback is not defined at HTMLSpanElement.onclick
My other idea was to add the function to the window object window.myCallback = ... inside my main index.js file to be loaded every time the app loads. This way it works but I have two issues.
My understanding is that this is not the correct React way to do it.
Whenever I click the span element the callback function is triggered twice and I cannot understand why.
Any suggestions?
Using "dangerouslySetInnerHTML" is ..."dangerous" as its name ^^, which is actually not pure React way, either.
However, If you have to do it, you can do something like this (take advantage of built-in jQuery inside React be default)
=====
EDITED VERSION FROM HERE: (use only 1 component)
export default class MyComponent extends Component {
componentDidMount() {
// using jQuery to manipulate DOM element form third-party source
// NB. you may think of using setTimeout here, to wait for the external source to be fully loaded here, of course it's not so safe
// but anyway, we are using "dangerouslySetInnerHTML" anyway => quite dangerous, though ^^
// setTimeout(function(){
$(document.findElementsByTagName("span")[0]).click(function(e){
// or perhaps $("#spanID").click if you can, just be careful between DOM element and react component
e.preventDefault();
// DO SOMETHING HERE, just like you do in the window.onload function
// or maybe you also need to get param values by getting $(this).data("...") or $(this).attr("ATTRIBUTE-NAME")
return false;
});
// });
}
render() {
return (
<div
dangerouslySetInnerHTML={{ __html: this.props.externalHTML }}
/>
);
}
}
=====
OLD ANSWER FROM HERE: (use 2 components)
ParentComponent:
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.callbackOnThisComponent = this.callbackOnThisComponent.bind(this);
}
callbackOnThisComponent(param1, param2, param3) {
// do whatever you like with the above params
}
render() {
return (
<ChildComponent triggerCallbackOnParent={this.callbackOnThisComponent} />
);
}
}
ChildComponent:
export default class ChildComponent extends Component {
componentDidMount() {
// using jQuery to manipulate DOM element form third-party source
let that = this;
// NB. you may think of using setTimeout here, to wait for the external source to be fully loaded here, of course it's not so safe
// but anyway, we are using "dangerouslySetInnerHTML" anyway => quite dangerous, though ^^
$(document.findElementsByTagName("span")[0]).click(function(e){
// or perhaps $("#spanID").click if you can, just be careful between DOM element and react component
e.preventDefault();
that.props.triggerCallbackOnParent(param1, param2, param3);
// or maybe you need to get param values by getting $(this).data("...") or $(this).attr("ATTRIBUTE-NAME")
return false;
}, that);
}
render() {
return (
<div
dangerouslySetInnerHTML={{ __html: this.props.externalHTML }}
/>
);
}
}
I just use the main React's idea, which is passing props downward to children components, and when you want to trigger a function upward from child component, create a callback function on parent. For your or anyone else's reference, this is my demonstration on how to pass callback function from parent to multi-level-children components:
Force React container to refresh data
Re-initializing class on redirect
if this doesn't work yet, feel free to show me some error logs, thanks

How do I call the iScroll refresh methode in a parent react component?

I am struggling currenlty with iScroll in combination with reactJS.
This code samples are written in typescript.
I created a wrapper class for iScroll:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
var iScroll = require('iscroll');
...
componentDidMount() {
this._initializeIScrollInstance();
console.log(this);
}
_initializeIScrollInstance() {
setTimeout(() => {
let element = ReactDOM.findDOMNode(this);
const iScrollInstance = new iScroll(element, this.props.options);
this._iScrollInstance = iScrollInstance;
}, 100);
}
render() {
return (
<div style={ this.props.style } >
{ this.props.children }
</div>
)
}
}
Then I use it like this in my sidebar class for instance.
<ScrollWrapper>
<SidebarMenu toggle={ this.toggle.bind(this) } />
</ScrollWrapper>
The problem I am facing is when I toggle a menu inside my sidebar. This means the height changes so I need to call the refresh methode for iScroll.
But how can I achieve this?
Can I get the _iScrollInstance in my parent component?
Its possible to keep a state inside my sidebar and pass it down to the ScrollWrapper as a property and watch for it in componentReceiveProps.
But this sounds like a cheap solution to me.
Anyone maybe have a better solution for that kind of problem?
Based on your code :
<ScrollWrapper>
<SidebarMenu toggle={ this.toggle.bind(this) } />
</ScrollWrapper>
I see the child component action (toggle) needs to do something with the parent component (scroll). The idiomatic way to do this is for the parent to give the child component a function (callback) that the child calls when it wants something in the parent to change.
Note: The recommeded way is to use flux ... but thats a whole other topic (lookup redux which is what I use).

Resources