render React component from a string - javascript

I have some React code in the string, for example:
const component = `
function App() {
return (
<div>
test
</div>
);
}
`;
And I want to be able to render that component from within browser, something like:
import React, { Component } from 'react';
import { render } from 'react-dom';
import * as babel from 'babel-standalone';
const babelCode = babel.transform(component, { presets: ['react', 'es2015'] }).code;
render(eval(babelCode), document.getElementById('WorkFlow'));
This particular example doesn't work but it shows what I'm looking for, any help appreciated!
Thanks!

Babel produces the code with "use strict" and eval() doesn't work with it well. First, we should remove that line manually.
const code = babelCode.replace('"use strict";', "").trim();
Ideally, after this following lines should work.
eval(code);
render(<App/>, document.getElementById('WorkFlow'));
Note that you don't need to put eval() inside render. It doesn't return your App function or anything. Instead, it will add App to context and we can use it after eval() statement.
But usually, React app has a compile step with webpack or similar tool and will complain about undefined App.
As a workaround, we can wrap our component with a Function which returns our component itself. Now we can call this function to get our component. But the context of wrapping function doesn't have React variable. So we have to pass it manually as a parameter. If you are going to use any other variable from the current context, you will have to pass those as well.
const code = babelCode.replace('"use strict";', "").trim();
const func = new Function("React", `return ${code}`);
const App = func(React)
render(<App/>, document.getElementById('WorkFlow'));
Hope this helps!

React will allow you to render either a Component or an Element. You can think of an Element as a raw HTML code in JSX, while a Component is a prototype, which inherits from React.Component. In your code you are trying to render a result of evaluating the babel transpiled code, which will fail (I'm not sure what it is, but it's probably undefined or null). If you want to make it work, first evaluate the code and then invoke the function to pass the Element code to the render function:
eval(babelCode); // now the App function has been defined and you can use it in the code
render(App(), document.getElementById('WorkFlow'));
// ^^ here the App function is being invoked
Old answer (I thought you were trying to pass the component as a file not and not as a variable to transpiler):
babel will never transpile strings, so this is not going to work out for you. You can however consider using a raw JS code instead of JSX as your string content. More about it you can read here: https://facebook.github.io/react/docs/react-without-jsx.html

Related

Why react use angular brackets in rendering the component

I am new to the react as my background is ruby, so maybe it look a silly or noob question.
i come to the article
"Every component must begin with a capital letter. And once a component is declared, it can be written and used very similarly to an HTML element." and also this
"To use this component in your application, use similar syntax as normal HTML: "
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a {this.state.color} Car!</h2>;
}
}
root.render(<Car color="red"/>);
we have a car component created using class component so my question here is Why we use angular bracket here for creating instance of Car class. is this a syntax of creating instance of class in react.
Or
To use this component we have to use similar syntax as HTML. why?
React uses angular brackets () in rendering an element as a result it permits you to incorporate the element as a JSX part. JSX may be a syntax extension for JavaScript that permits you to write down HTML-like code in your JavaScript files. it's not obligatory to use JSX with React, however, it's a preferred alternative, as a result, it makes it easier to grasp the structure of your elements and the way they relate to the DOM.
To render an element in React, you'll use the ReactDOM.render() methodology and pass it to the element you wish to render further as a DOM part.
import React from 'react';
import ReactDOM from 'react-dom';
const MyComponent = () => <h1>Hello, World!</h1>;
ReactDOM.render(<MyComponent />, document.getElementById('root'));
The MyComponent operation is wrapped in angular brackets () and passed to the ReactDOM.render() methodology as a JSX part. This tells React to treat the operation as an element and render it within the DOM part with the id of the root.
Hopefully this helps. Before React we needed an index.html File and had to call your javascript.js file within your HTMLenter image description here. example: in HTML, if we wanted to select a Button in javascript and add an onClick event we had to call the button but be specific as possible, so we had to add a class,ID, etc... Import your button to your javascript file like car= document.getElementById("car1")
and then add a onclick event. as you can see this can be exhausting. worst part is you cant add HTML in your Js file, so no tags, etc.. so the way to make things easier in HTML is adding brackets. React allows you to use HTML and Js syntax.
in your example: return I am a {this.state.color} Car!;
we are telling React we have h2 from HTML but anything within { } is Javascript. as you can see React just makes easier to use HTML and javascript in the same file

Use Hook in function result in invalid hook call

I am currently rewriting my website into a webapp with ReactJS, and have a little trouble using and understanding hooks. I wrote a custom hook "useFetch" that works, never had any problems with it until now : I am currently trying to use my hook in a function like this :
import useFetch from '../../../hooks/useFetch';
import {clientGenerateProcessScreen, clientClearProcessScreen} from '../../../utils/processScreens';
function myFunction (paramName, paramType, paramDesc) {
let process_screen = clientGenerateProcessScreen ();
let rqt_url = `/fileNameA.php`;
if (paramType!= "a") rqt_url = `/fileNameB.php`;
const { data, isLoading, error } = useFetch(rqt_url);
if (!isLoading && data.success) {
doSomethingA ();
} else {
showErrorMessage ();
}
}
export default myFunction;
The function is called from an onClick on a react component. It should theorically work fine, however, I always end up having this error :
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
I do not understand where the error here is. I am using my hook at the top of a function, not in a condition or anything that might break hook rules. I have tried importing React and ReactDOM in my function file, but this doesn't solve any of my issues. I am guessing I might have missed something basic or simple, yet can't find what...
Firstly, you implemented a custom hook, therefore it should be prefixed with the "use" word: useMyFunction, for more context see Do React hooks really have to start with "use"?.
Now that you know its a hook and not a util function, it must follow hooks API ("Rules of Hooks"), and one of those rules is that you must call it in a top level, i.e You CANT use it as a callback.
For solving it, it requires a logical change, its not something you have a step-by-step fixing guide, rethink its logical use.

Appending JSX in React Native

I'm searching for a way to add a JSX element programmatically in React Native. Not conditionally.
It needs to be independent function, so far I couldn't find anything about this. Let me give you code example;
const appendJSX = () => {
const jsx = <Text> Hello! </Text>
append(jsx) // <---- can we do something like this?
}
let's say I call this function with useEffect and it should add whatever jsx I have inside the function. Up until this point I always see things like pushing inside of an array or something like that.
UPDATE
Equivalent behaviour that works on web;
useEffect(() => {
const div = document.createElement("div");
div.innerText = "appended div"
document.body.append(div)
}, [])
As you can see we don't have to touch any JSX in application. Reaching document.body and appending whatever we want is possible in React Web. But how can we achieve this in React Native?
Not quite sure what you want to do, but as for to add a JSX manually. Here's the answer.
JSX is already part of the language in most of the cases.
const a = <Text />
export default a
Will translates into:
const a = createElement(Text, null, null)
export default a
Therefore in most of common cases, if you continue using React somewhere else, then the variable a holds a React element without any compilation error.
You might wonder what a actually really holds, it's an object:
const a = {
$$typeof: Symbol(ReactElement),
props: null,
type: Text
}
So you can see the only dependencies in above piece is Text and the ReactElement Symbol. As long as you can resolve them, you are good to export this to anywhere. The latter is normally taken care by Babel.
NOTE:
There's a difference between Text and <Text />. If you just want to export a Text which is a function component, there'll tutorial online, also you can dig into any third party library, because essentially that's what they do, export Text so other people can use it.

Confusion with default import of React

To import React we write import React from 'react'.
But this is a default export right ? So if I change its name to something else other than React it should also work. But it doesn't work. Can anyone please explain why?
Essentially, JSX compilers (like Babel/TypeScript) convert the JSX code to pure JavaScript.
For example, the following JSX code:
const Element = () => (
<div>
Hey there
</div>
);
is compiled into:
const Element = () => (
React.createElement("div", null, "Hey there")
);
Which is now valid JavaScript that can be parsed by the browser.
As you may have noticed, it uses the React.createElement function to create the div. This is why changing the name of the import doesn't work - the compiler still tries to use React.
Babel lets you configure this using the pragma option, if desired, allowing you to use a different function name.
TypeScript can do the same using the jsxFactory compiler option.
It works so, as you use Babel, or something similar, to translate JSX.
So when you input something like this:
function AComponent() {
return <div>Hello world</div>
}
You will get the next transpiled code:
"use strict";
function AComponent() {
return React.createElement("div", null, "Hello world");
}
By this reason you should use the definite name of React.
You can try it here: https://babeljs.io/repl#?babili=false&browsers=&build=&builtIns=false&spec=false&loose=false&code_lz=AQ4MwVwOwYwFwJYHsrAIIGEkFsAOKBTKOACgEpgBvAKFBACcC4J7UAeAEwQDcA-ACQIAbIUmAB3JPSEc2Aei59aoAL5A&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=es2015%2Creact%2Cstage-2&prettier=false&targets=&version=7.4.4&externalPlugins=

Vue Component Versioning, is something along these lines possible?

I currently import my component dynamically as they are needed, however if a lot of changes are required on a component, I would want to make a new version of it, however it would still be the same component in a way.
I have the following within my app.js:
Vue.component( 'favourites-panel', () => import('./components/Favourites/Panel.vue' );
Can I change the above to something like this and get the version from the prop? Obviously this is theoretical code!
Vue.component( 'favourites-panel', (e) => import('./components/Favourites/Panel' + e.version + '.vue' );
This is how i'm calling my component:
<favourites-panel version="1"></favourites-panel>
No, that's not possible "versioning" a component using the props object.
First of all, you need to understand what you are doing: Vue.component is a function to load globally all the components you want. You can pass an absolute path or if required, a promise.
In this case, you want to load your component asynchronously and the statement import, return a Promise. If you inspect the e property you'll see that is the resolve callback.
Writing:
Vue.component( 'favourites-panel', () => import('./components/Favourites/Panel.vue' );
or:
Vue.component('favourites-panel', function (resolve) {
require(['./components/Favourites/Panel.vue'], resolve)
})
It's the same thing, both returns a Promise object.
For solving your problem you can add an environment variable and then load the
component according to the value of that particular environment variable.
No, this is entirely the wrong approach to both source control and dependency management. You should instead be creating NPM modules of your component(s) and then if for some reason you need to use an old one again you can npm install the old version.

Categories

Resources