how to render multiple children without JSX - javascript

How to write this without using JSX?
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList />
<CommentForm />
</div>
);
}
});
This comes from the react.js tutorial: http://facebook.github.io/react/docs/tutorial.html
I know I can do the following:
return (
React.createElement('div', { className: "commentBox" },
React.createElement('h1', {}, "Comments")
)
But this only adds one element. How can I add more next to one another.

You can use the online Babel REPL (https://babeljs.io/repl/) as a quick way to convert little chunks of JSX to the equivalent JavaScript.
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement("div", {className: "commentBox"},
React.createElement("h1", null, "Comments"),
React.createElement(CommentList, null),
React.createElement(CommentForm, null)
)
);
}
});
It's also handy for checking what the transpiler outputs for the ES6 transforms it supports.

insin's answer is the direct translation, however you may prefer to use factories.
var div = React.createFactory('div'), h1 = React.createFactory('h1');
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
div({className: "commentBox"},
h1(null, "Comments"),
React.createElement(CommentList, null),
React.createElement(CommentForm, null)
)
);
}
});
createFactory essentially partially applies createElement. So the following are equivalent:
React.createElement(c, props, child1, child2);
React.createFactory(c)(props, child1, child2);
If you're just using es6 but aren't fond of JSX you can make it less verbose with destructuring assignment. See this jsbin for an interactive example using 6to5 instead of jsx.
var [div, h1, commentForm, commentList] = [
'div', 'h1', CommentForm, CommentList
].map(React.createFactory);

if you have a variable number of children then you can use that:
Using apply function which take an array of parameters.
React.createElement.apply(this, ['tbody', {your setting}].concat(this.renderLineList()))
where renderLineList is for instance:
renderLineList: function() {
var data=this.props.data;
var lineList=[];
data.map(function(line) {
lineList.push(React.createElement('tr', {your setting}));
});
return lineList;
}

You just add them one after another as children to your parent component,
return React.createElement("div", null,
React.createElement(CommentList, null),
React.createElement(CommentForm, null)
);

I had this problem, it took a while to solve by stepping through the interpreter source code:
var arrayOfData = [];
var buildArray = (function () {
var id;
var name;
return{
buildProc(index, oneName){
id = index;
name = oneName;
arrayOfData[index] = (React.createElement('Option', {id},name));
}
}
})();
// then
this.state.items = result;
var response = parseJson.parseStart(this.state.items);
var serverDims = response.split(":");
for (var i = 1; i < serverDims.length; i++) {
buildArray.buildProc(i, serverDims[i] )
}
// then
render(){
const data = this.props.arrayOfData;
return (
React.createElement("select", {},
data
)
// {data} Failed with "object not a valid React child, data with no curly's worked
)
}

Related

Regarding creating React components

I am learning React and ES6. In the process of learning, I stumbled upon a code snippet which I have mentioned below.
import { getBoxStyle } from './PythagorasTree.js'
export const TreeBox = (props) => {
const style = getBoxStyle(props)
const baseProps = Object.assign({}, props, {
level: props.level + 1,
})
// What this function does
const leftChild =
props.level < props.totalLevels &&
React.createElement(TreeBox,
Object.assign({}, baseProps, { right: false })
)
const rightChild =
props.level < props.totalLevels &&
React.createElement(TreeBox,
Object.assign({}, baseProps, { right: true })
)
return React.createElement('div', { style },
leftChild,
rightChild
)
}
ReactDOM.render(
React.createElement(TreeBox, {
level: 0,
totalLevels: 5,
heightFactor: 0.37,
lean: -0.10,
size: 100,
}),
document.getElementById('app')
)
My question here is what does variable do in below piece of code
// What this function does
const leftChild =
props.level < props.totalLevels &&
React.createElement(TreeBox,
Object.assign({}, baseProps, { right: false })
)
According to the code, it should return some TreeBox components to the DOM but i didn't understand if there is a loop or recursive method in that. I can see the comparison but I can't able to find any recursion or looping in that.
var i = 10;
var j = 5;
var test = function(){ j++; console.log('Hello'); }
var hello = j < i && test();
Is it correct way to interpret? It is not printing recursively. How do I interpret that?
If props.level is less than props.totalLevels then Create and return a new React element of the given type. The type argument can be either a tag name string (such as 'div' or 'span'), a React component type (a class or a function), or a React fragment type.
ex:
React.createElement(
type,
[props],
[...children]
)
&& just means if what comes before is true then execute what comes after.

Pass function from parent to child

I'm a little weak in javascript.
I'm inspiring myself from this answer to pass a function from parent to child in REACT and I'm having a little difficulty.
Could someone help me correct my code?
Thanks!
var List = React.createClass({
deleting: function(test){
console.log(test);
},
render: function() {
var all = this.props.activities;
var test = List.deleting;
var list = all.map(function(a){
return (<ListItem act={a} del={test}>);
});
return (
<ul> {list}
</ul>
);
}
});
var ListItem = React.createClass({
deleting: function(e){
this.props.del(e.target.parentNode.firstChild.innerHTML);
},
render: function(){
return (
<li key={this.props.act}>{this.props.act}
<div onClick={this.deleting}>X</div>
</li>
);
}
});
The error I get:
You need pass reference to method .deleting that is part of List Object, now you are trying pass var test = List.deleting; that is undefined. In order to this in .map, refers to List, you should set this for .map by yourself - to do that just pass (in our case it should be this because this in render method refers to List) second argument to .map, and pass to del= attribute reference to method this.deleting.
Also set key attribute for ListItem, and in React all tags must be closed - so add /> ( now you are getting error because you have not closed tag ListItem) in the end of ListItem tag
var List = React.createClass({
deleting: function(test) {
console.log(test);
},
render: function() {
var all = this.props.activities;
var list = all.map(function(a) {
return (<ListItem key={a} act={a} del={this.deleting} />);
}, this);
return <ul> {list} </ul>
}
});
Example

React.js click event inside map function [duplicate]

I used this article as an example (React way), but it is not working for me. Please point me to my mistake, as I can't understand what's wrong.
This is the error I see:
Uncaught TypeError: this.props.onClick is not a function
Here is my code:
// PARENT
var SendDocModal = React.createClass({
getInitialState: function() {
return {tagList: []};
},
render: function() {
return (
<div>
{
this.state.tagList.map(function(item) {
return (
<TagItem nameProp={item.Name} idProp={item.Id} onClick={this.HandleRemove}/>
)
})
}
</div>
)
},
HandleRemove: function(c) {
console.log('On REMOVE = ', c);
}
});
// CHILD
var TagItem = React.createClass({
render: function() {
return (
<span className="react-tagsinput-tag">
<span>{this.props.nameProp}</span>
<a className='react-tagsinput-remove' onClick={this.HandleRemove}></a>
</span>
)
},
HandleRemove: function() {
this.props.onClick(this);
}
});
Thanks in advance!
The issue is that this inside the map callback does not refer to the React component, hence this.HandleRemove is undefined.
You can set the this value explicitly by passing a second argument to map:
this.state.tagList.map(function() {...}, this);
Now this inside the callback refers to the same value as this outside the callback, namely the SendDocModal instance.
This has nothing to do with React, it's just how JavaScript works. See How to access the correct `this` context inside a callback? for more info and other solutions.
Try the following:
var SendDocModal = React.createClass({
getInitialState: function() {
var item = {};
item.Name = 'First';
item.Id = 123;
var item2 = {};
item2.Name = 'Second';
item2.Id = 123456;
return {tagList: [item,item2]};
},
HandleRemove: function(c){
console.log('On REMOVE = ', c);
},
render: function() {
return (<div>
{this.state.tagList.map(function(item){
return(
<TagItem nameProp={item.Name} idProp={item.Id} key={item.Id} click={this.HandleRemove}/>
)}, this)}
</div>
)
}
});
// CHILD
var TagItem = React.createClass({
handleClick: function(nameProp)
{
this.props.click(nameProp);
},
render: function(){
return(
<span className="react-tagsinput-tag" ><span onClick={this.handleClick.bind(this, this.props.nameProp)}>{this.props.nameProp}</span><a className='react-tagsinput-remove' ></a></span>
)
}
});
Few changes:
Added 'this' after the tagList mapping. To be honest I am not entirely sure why - perhaps a more experienced programmer can tell us.
Added a key to each TagItem. This is recommended and an the console will inform you that you should do this so that if the state changes, React can track each item accordingly.
The click is passed through the props. See React js - having problems creating a todo list

REACTJS getDOMNode Error on undefined dynamic refs

I am trying to get a DOM node ref from a dynamic object but I am getting the following error in the Chrome console:
Uncaught TypeError: Cannot read property 'getDOMNode' of undefined.
https://jsfiddle.net/ux4rL8sf/6/
var Hello = React.createClass({
getInitialState: function () {
return {
currentItems : [{"id":"1"} , {"id":"2"} , {"id":"3"}]
};
},
onRowClick: function (i) {
var x;
if (i == 'abs') {
x = this.refs[i].getDOMNode().scrollHeight;
} else {
x = this.refs['row' + i].getDOMNode().scrollHeight;
}
alert(x);
},
render: function() {
var Items = this.state.currentItems.map(function(tv) {
return (<div refs={"row" + tv.id} onClick={this.onRowClick.bind(this, tv.id)} > {tv.id}</div>);
}.bind(this)
);
return (<div> {Items} <div ref="abs" onClick={this.onRowClick.bind(this, 'abs')}>Test </div> </div>) ;
}
}
);
React.render(<Hello />, document.getElementById('container'));
In the callback you provide to map when creating the Items variable in your render method, you have
return (<div refs={...
I think you want
return (<div ref={...
instead.
On line 22 of your fiddle, you use refs instead of ref. I think that should fix your problem.

How to rebuild a existing Dom in reactjs?

I am currently trying to get reactJS working with the following Setup:
I am getting a xml-DOM from the Server. Its a server side rendered "custom" DOM, which normaly gets consumed by another client (not html, but java) which renders components.
<row id="a">
<label id="aa" width="140" text="Title" />
<field id="ab" bgpaint="" width="200" text="" enabled="true" />
</row>
I defined some ReactComponents with React.createClass(). So I have a Label, a Field and a Row (div).
Currently I cannot work out a way to render the Components of the xml-DOM with react.
I am going trough the xml-DOM and got the snippet from above. If I find a "row" shell I call React.createElement(Row, {}, ?)? But I i dont know what children will be to fill the '?' before I go deeper into the xml-DOM.
If I walk through the xml-DOM until I got a "endNode" with no children, how can i create the react elements from bottom to top? Do I have to create a super String and somehow call it as javascript.
Is there a way to create a Row, and afterwads add the children? Do I have to use the components props?
Something like:
//<row> found
var newRow = React.createElement(Row, {}, ?);
...
//found the label in the row
var newLabel = React.createElement(Label, {}, "Title");
newRow.add(newLabel);
I can hardly come to a solution - is it possible to do with react? Or am I trying to do something which react is not made for? Probably I do not understand the child concept totally.
Or maybe its not really a react-Problem itself...
Any hints for me?
greetz
Create the children array before you call createElement. For example (jsfiddle):
function pascalize(str) {
return str.split("-").map(function(name) {
return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
}).join("");
}
function attrsToProps(attrs) {
var obj = {};
for (var i = 0; i < attrs.length; ++i) {
obj[attrs[i].nodeName] = attrs[i].value;
}
return obj;
}
function toReact(node, components) {
if (node.nodeType === 1) {
var children = [].map.call(node.childNodes, function(child) {
return toReact(child, components);
});
return React.createElement(components[pascalize(node.nodeName)],
attrsToProps(node.attributes),
children);
} else if (node.nodeType === 3) {
return (node.nodeValue + "").trim();
}
return "";
}
function xmlToReactComponents(xmlDom, components) {
if (xmlDom && xmlDom.documentElement) {
return React.createElement("div", [], [].map.call(xmlDom.documentElement.childNodes, function(child) {
return toReact(child, components);
}));
}
}
The usage in jsfiddle is:
var xml = document.querySelector("#xml").innerHTML;
var parser = new DOMParser();
var dom = parser.parseFromString(xml, "text/xml");
var defaultClass = {
render: function() {
return React.createElement("div", {}, "id: " + this.props.id, this.props.children);
}
};
var components = {
Row: React.createClass(defaultClass),
Label: React.createClass(defaultClass),
Field: React.createClass(defaultClass)
}
var result = xmlToReactComponents(dom, components);
React.render(result, document.body);
You need to pass all the components the xml could create in the object otherwise whole thing fails

Categories