with React v0.12 the #jsx pragma is gone which means it is no longer possible to output jsx with anything other than the React.METHODNAME syntax.
For my use case I am trying to wrap the React object in another object to provide some convenience methods thus, in my component files, I want to be able to write:
var myConvenienceObject = require('React-Wrapper');
var Component = myConvenienceObject.createSpecializedClass({
render: function () {
return <div />
}
})
However the jsx compiler automatially converts <div /> into React.createElement("div", null)
With older versions of React it was possible to handle this using the pragma at the top of the file. However, since that has been removed, I was wondering if there was any way currently to change the name of the object compiled by jsx so <div /> would be transformed into myConvenienceObject.createElement("div", null)
No, it's no longer possible to use a custom prefix for JSX. If you need to do this, you'll need to modify the JSX transform code, or create a fake React.
var React = require('react'), FakeReact = Object.assign({}, React, {
createElement: function(component, props, ...children){
// ...
// eventually call the real one
return React.createElement(component, props, ...children);
}
});
module.exports = FakeReact;
And then to use it you import the fake react and call it React.
var React = require('fake-react');
// ...
render: function(){ return <div />; }
If you would like to make some elements contains in your myConvenienceObject, you could consider the children props as shown in the doc. But this may need some changes in the myConvenienceObject too, to accept the children.
By the way, i'm not sure where is this createSpecializedClass functions comes from and what it does
Related
I'm working on a simple blog/CMS tool. In authoring content, I'm supporting an option to enter raw html/css. The user enters this content into a text area, and I can render this into a page using dangerouslySetInnerHtml. That works fine.
However, I'd really like to embed some React components the content as well. Ideally I'd like to enter something like this into a textarea...
<div>
<p>Some content</p>
<MyPictureComponent url="..." />
</div>
...and then render that into a page and have it create the MyPictureComponent.
I'll be storing the above "code" in a database, and rendering it dynamically as users view the "post". Is it possible to rendering that raw text as functioning React?
I saw this project (HTML to React), which seemed promising, bu that seems to only parse the HTML given to it, not tags for React components.
I found a way to do what I want, with the caveat that it's somewhat manual, and potentially dangerous. However, in my case, I'm creating a blog/CMS for a very limited audience, and the concern about users potentially inserting harmful content is non-existent.
My approach ended up using html-to-react (https://www.npmjs.com/package/html-to-react). Html-to-react accepts a string (containing raw HTML markup), and transforms it into a proper React component. By default, its parse() method doesn't properly handle React components (it just turns them into lower-case-named html elements). However, the library has a parseWithInstructions, which allows you to control how individual nodes in the component are rendered.
In my case, I want to enable certain React components to be rendered. One of those is my ExternalLink component. What follows is the method I use to transform some user-entered raw HTML into a React component that properly rendered my components.
updatePreview() {
// Combine the user-entered CSS and the user-entered HTML into a single string.
let outputPreview = "<div><style>" + this.state.cssValue + "</style><div>" + this.state.inputValue + "</div></div>";
let htmlToReactParser = new HtmlToReact.Parser();
let processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);
let processingInstructions = [
{
// Custom <ExternalLink> processing
shouldProcessNode: function (node) {
return node.name === 'externallink';
},
processNode: function (node, children) {
let attribs = node.attribs;
return <ExternalLink {...attribs}>{children}</ExternalLink>
}
},
{
// Anything else
shouldProcessNode: function (node) {
return true;
},
processNode: processNodeDefinitions.processDefaultNode
}];
// Convert the HTML into a React component
let reactComponent = htmlToReactParser.parseWithInstructions(outputPreview, () => true,
processingInstructions);
// Now that we have a react component, we set it to the state.
// Our render() method includes a "{this.state.outputPreview}", which causes the
// component to be rendered.
this.setState({outputPreview: reactComponent, refreshPreviewTimer: null});
}
Note that outputString in the first line of the method will contain some raw text like this:
"<div>
<style></style>
<div>
<p>Here's a link:<p>
<ExternalLink url="http://www.google.com">Google</ExternalLink>
</div>
</div>"
There are some approaches I'll take to generalize this approach more, using a dictionary of strings to enable support for a wider range of Components. I'll also look at some approach to automatically importing the desired Component. (Currently, I'm manually importing all supported components.)
So, all credit goes to the author of html-to-react, though I may encourage him to include an example of rendering child components.
The project has the following reference, which returns a string:
const left = slide.imageLeft; // introLeft
And further renders it inside React Component. But it returns as a string styles.imageLeft and since webpack doest convert it into corresponding bundled class like 914u923asdsajdlj1l23 the styles are not applied.
<div className={`styles.${left}`}> </div>
P.S I did try to eval, but it drops 2 errors.
There is an internal error in the React performance measurement code. Did not expect componentDidMount timer to start while render timer is still in progress for another instance.
And
ReferenceError: styles is not defined
Can you please suggest the possible ways to achieve dynamic class generation for css-loader.
You have to define the style within the render(), or within the component definition, like this
render: function(){
var myStyle = {
// your style rules go here
};
return(
<div style={myStyle}>
{this.props.children}
</div>
)
}
in a way, this is already dynamic, because all you have to do is to change to style and it'll make sure that the component will re-render on update
How would I take a string, and convert it to jsx? For example, if I bring in a string from a textarea, how could I convert it to a React element;
var jsxString = document.getElementById('textarea').value;
What is the process I would use to convert this on the client? Is it possible?
You can consider using the React attribute dangerouslySetInnerHTML:
class YourComponent{
render() {
someHtml = '<div><strong>blablabla<strong><p>another blbla</p/></div>'
return (
<div className="Container" dangerouslySetInnerHTML={{__html: someHtml}}></div>
)
}
}
Personally, I love to do it just like in the previous answer which recommends the usage of dangerouslySetInnerHTML property in JSX.
Just for an alternative, nowadays there is a library called react-html-parser. You can check it and install from NPM registry at this URL: https://www.npmjs.com/package/react-html-parser. Today's weekly download statistic for that package is 23,696. Looks a quite popular library to use. Even it looks more convenient to use, my self, still need more read and further consideration before really using it.
Code snippet copied from the NPM page:
import React from 'react';
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
class HtmlComponent extends React.Component {
render() {
const html = '<div>Example HTML string</div>';
return <div>{ ReactHtmlParser(html) }</div>;
}
}
Here's how you can do it, without using dangerouslySetInnerHTML.
import React from "react";
let getNodes = str =>
new DOMParser().parseFromString(str, "text/html").body.childNodes;
let createJSX = nodeArray => {
return nodeArray.map(node => {
let attributeObj = {};
const {
attributes,
localName,
childNodes,
nodeValue
} = node;
if (attributes) {
Array.from(attributes).forEach(attribute => {
if (attribute.name === "style") {
let styleAttributes = attribute.nodeValue.split(";");
let styleObj = {};
styleAttributes.forEach(attribute => {
let [key, value] = attribute.split(":");
styleObj[key] = value;
});
attributeObj[attribute.name] = styleObj;
} else {
attributeObj[attribute.name] = attribute.nodeValue;
}
});
}
return localName ?
React.createElement(
localName,
attributeObj,
childNodes && Array.isArray(Array.from(childNodes)) ?
createJSX(Array.from(childNodes)) :
[]
) :
nodeValue;
});
};
export const StringToJSX = props => {
return createJSX(Array.from(getNodes(props.domString)));
};
Import StringToJSX and pass the string in as props in the following format.
<StringToJSX domString={domString}/>
PS: I might have missed out on a few edge cases like attributes.
I came across this answer recently and, it was a good deal for me. You don't need to provide a string. Returning an array of JSX elements will do the trick.
We can store JSX elements in JavaScript array.
let arrUsers = [<li>Steve</li>,<li>Bob</li>,<li>Michael</li>];
and in your HTML (JSX) bind it like,
<ul>{arrUsers}</ul>
As simple as it is.
If you consider string
<div>Hello World</div>
If we are very strict, this actually is the valid JSX. The question is how to compile this JSX string into React code.
Easiest and the recommended way is to download some library like Babel and use it to transform the code. Babel can run in the Browser like the repl does.
It is also possible to transform JSX to other formats, but in this case you have to find a compiler or create one yourself.
The steps to create the JSX => React transformation yourself is:
transform the code string into AST representation
parse the AST and output code back to string
So you need somekind of AST parser like espree supporting JSX and then you can create a code which walks the AST tree and outputs something, like React -code out of it.
The AST tree of JSX data consists of normal JavaScript AST together with JSX nodes. The parser should walk through the tree and transform the JSX nodes into normal JavaScript code.
If you compile to React and encounter a JSX node with tag "div" you should compile that into React.createElement("div",... call with attributes and subnodes found under that AST node inserted as parameters of that call.
I have created a small AST Walker, which can process AST tree, ASTWalker, which can be used to transform the AST tree into some output format, like React or DOM.
On-line example of how to use it is here:
http://codepen.io/teroktolonen/pen/KzWVqx?editors=1010
The main code looks like this:
// here is the JSX string to parse
var codeStr = "<div>Hello world</div>";
var walker = ASTWalker({
defaultNamespace: "react",
});
// compile AST representation out of it.
var rawAST = espree.parse(codeStr, {
ecmaVersion: 6,
sourceType: "script",
// specify additional language features
ecmaFeatures: {
// enable JSX parsing
jsx: true
}
});
// then you can walk the walk to create the code
walker.startWalk( rawAST, {} );
var code = walker.getCode();
console.log(code);
document.getElementById("sourceCode").innerHTML = code;
DISCLAIMER: The library is not intented for compiling into React. It is mostly used with defaultNamespace: "DOM", using it to compile into plain JavaScript + DOM representation. Trying anything more complicated than simple tags may result as an error.
The important thing is to notice that React is not only possible output format for JSX.
I've been using html-to-react with some success (self closing tags cause a problem though, but a fix is in the pull requests...) to parse markup strings as DOM like objects, and in turn React elements. It's not pretty, and if you can avoid it, do so. But it gets the job done.
html-to-react at github: https://github.com/mikenikles/html-to-react
Use React-JSX-Parser
You can use the React-JSX-Parser library dedicated for this.
npm install react-jsx-parser
here is the repo
html-react-parser is what you need.
import parse from 'html-react-parser';
import React from 'react';
export default function YourComponent() {
someHtml = '<div><strong>blablabla<strong><p>another blbla</p/></div>'
return (
<div className="Container">{parse(someHtml)}</div>
)
}
Here's a little utility component for this:
const RawHtml = ({ children="", tag: Tag = 'div', ...props }) =>
<Tag { ...props } dangerouslySetInnerHTML={{ __html: children }}/>;
Sample usage:
<RawHtml tag={'span'} style={{'font-weight':'bold'}}>
{"Lorem<br/>ipsum"}
</RawHtml>
First you can change it to a non-string array and then use it as JSX
class ObjReplicate extends React.Component {
constructor(props) {
super(props);
this.state = { myText: '' };
}
textChange=(e) =>{this.setState({ myText: e.target.value })};
render() {
const toShow = this.state.myText;
var i=1;
var allObjs=new Array;
while (i<100){
i++;
allObjs[i] = <p>{toShow}</p>; //non-sting array to use in JSX
}
return (
<div>
<input onChange={this.textChange}></input>
{allObjs}
</div>
);
}
}
ReactDOM.render(<ObjReplicate/>,document.getElementById('root'));
You need to use babel with preset react
npm install --save-dev babel-cli babel-preset-react
Add the following line to your .babelrc file:
{
"presets": ["react"]
}
Then run
./node_modules/.bin/babel script.js --out-file script-compiled.js
You can find more info here
This is regarding non-standard attributes. https://facebook.github.io/react/docs/tags-and-attributes.html
In react I have done this:
React.createElement('div', {image:'blah', etc:'blah'});
I need image and etc to be set on the element with setAttribute, and I need react to use its smarts to maintain it as it changes.
A solution here https://stackoverflow.com/a/21654914/1828637 says to add it on componentDidMount but this is not a solution. The attribute will not be maintained as it changes by the react framework.
Is there anyway to tell react to set the attribute on my custom tags?
In react 16 custom attributes are now possible
// Your code:
<div mycustomattribute="something" />
// React 15 output:
<div />
// React 16 output:
<div mycustomattribute="something" />
react 16 custom attributes
This solution is to build on the linked answer by using the React lifecycle method componentWillReceiveProps to update the DOM element attributes with every change to props. For more information about all the lifecycle methods, see http://facebook.github.io/react/docs/component-specs.html.
(Since componentWillReceiveProps can be called more often than when the props actually change, you may wish to compare the props before actually setting them on the node.)
I've provide fiddle you can play with: https://jsfiddle.net/p4h267bo/ and the relevant part of the code is excerpted here:
var Hello = React.createClass({
componentDidMount() {
this.mirrorProps(this.props);
},
componentWillReceiveProps(nextProps) {
this.mirrorProps(nextProps);
},
mirrorProps(props) {
var node = ReactDOM.findDOMNode(this);
node.setAttribute('name', props.name);
},
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
Another alternative is to change the name of the attribute to something that react supports (such as the data-* attributes) :
render() {
return (
<div data-image='blah' data-etc='blah' />
);
}
link to other supported attributes: https://facebook.github.io/react/docs/dom-elements.html
I have a stateless functional component in React 0.14 that worked in React 0.13, but now returns the following error:
No render method found on the returned component instance: you may
have forgotten to define render, returned null/false from a
stateless component, or tried to render an element whose type is a
function that isn't a React component.
This is my component:
function ToggleDisplay(props) {
//should render a <noscript> per React's implementation
if(props.if === false) {
// return <noscript></noscript>; //do I have to do this manually now?
return null;
}
let style = {};
if(shouldHide(props)) {
style.display = 'none';
}
return (
<span style={style} {...props} />
);
}
Do I have to manually return a <noscript> now? Is there another way to return null in stateless component?
As of React 15.0, you can return null from a stateless functional component. (See #5355). No more having to return <noscript /> 🎉
The change that made this possible is that React removed support for component classes that don’t inherit from React.Component, meaning they can reliably differentiate between React components (classes that inherit React.Component) and functional stateless components. So the PR to enable the functionality just involved removing and simplifying the code that instantiates the components.
Looks like not, this is a technical constraint in Javascript. To support arrow functions and plain functions as "components" React needs to know if we can call new on them.
We can call new on everything if they're plain functions as long as
they return a ReactElement. However, that won't work for
null/false/string return values and we want to support those too. We
also can't call new on arrow functions. Likewise, we can't NOT call
new on classes.
Relevant GitHub Issue