React.js this.props.data.map() is not a function - javascript

I'm messing around with react and trying to parse and render a json object. Right now, I'm just setting it with a hard-coded object for testing and not getting it from an ajax call.
<script type="text/jsx">
var Person = React.createClass({
render: function() {
return (
<div>
<p className="personName"></p>
<p className="personSA1"></p>
<p className="personSA2"></p>
<p className="zip"></p>
<p className="state"></p>
<p className="country"></p>
</div>
);
}
});
var PersonDiv = React.createClass({
render: function() {
var personNodes = this.props.data.map(function(personData){
return (
<Person
personName={personData.person.firstname}
personSA1={personData.person.street1}
personSA2={personData.person.street2}
zip={personData.person.zip}
state={personData.person.state}
country={personData.person.country}>
</Person>
)
});
return (
<div>
{personNodes}
</div>
);
}
});
React.render(
<PersonDiv data={data} />,
document.getElementById('jsonData')
);
I'm setting the data variable with
<script>
var data = "[" + '<%=data%>' + "]";
</script>
The data object is one that I'm creating on the java side of a portlet. I know that the json is valid, because I can use JSON.parse(json) to parse and traverse the string, but I keep getting that map() is not a function.

It appears that your data is not a json object, it is a string. You probably need to run data = JSON.parse(data); to convert your data into an actual javascript object to be able to use it. An easy test for this would be to run
<script>
var data = "[" + '<%=data%>' + "]";
console.log(data);
console.log(JSON.parse(data));
</script>
You should notice the difference.

You are passing result of console.log as first parameter to React.render:
React.render(
console.log("inside render"),
<PersonDiv data={data} />,
document.getElementById('jsonData')
);
It should be like:
console.log("will render");
React.render(
<PersonDiv data={data} />,
document.getElementById('jsonData')
);

Related

React.js Object.entries().map() not rendering list contents [duplicate]

I am new to React JS, I was testing out some functions in fiddler. I am not sure why I get an error pointing to the map function. I am not able to render the array i defined.
Relevant snippet:
{this.props.data.productSpecs.map(function(productSpec){
<b>Category Name:</b> {productSpec};
})}
Full code:
var productCategory = {
productName: 'SamamgaTV1',
productCategory: 'Television',
productSpecs: ['32inch','black','hd']
};
var ProductComponent = React.createClass({
render: function() {
return( <div>
<h2>Product</h2>
<b>Product Name:</b> {this.props.data.productName}
<h2>Category</h2>
<b>Category Name:</b> {this.props.data.productCategory}
<h2>Specs</h2>
{this.props.data.productSpecs.map(function(productSpec){
<b>Category Name:</b> {productSpec};
})}
</div>);
}
});
ReactDOM.render(
<ProductComponent data={productCategory} />,
document.getElementById('container')
);
First you missed to return, then you must return ONE element.
Here you return a <p> and a TextNode
Moreover you need to provide a unique key.
Try with this :
{this.props.data.productSpecs.map(function(productSpec, i){
return <span key={i}><b>Category Name:</b> {productSpec}</span>;
})}
You need to return value from map handler.
{this.props.data.productSpecs.map(function(productSpec){
return (<span><b>Category Name:</b> {productSpec}<span>);
})}
If you do not want to (or can't in some situations) wrap content in span, you can create & return fragment (very handy)
const createFragment = require('react-addons-create-fragment');
{this.props.data.productSpecs.map(function(productSpec){
return createFragment({
bold: <b>Category Name:</b>,
spec: productSpec,
});
})}
It might be that you are using a string so you have to use the split method and pass in an empty string such as myValue.split('').map();

Embeding JSX as a string variable into other JSX code in React JS

I have JSX code but it is within a string. trying to inject that code inside other JSX inside a React Component and having trouble...
I am using dangerouslySetInnerHTML however the JSX is being treated as HTML somehow. I have the className = "test" in JSX format... So, when rendered it has HTML class of test (which is red background)
React component trying to inject a JSX string into other JSX code
createMarkup(){
var htmlString = '<div className="test">TESTING</div>';
return {__html : htmlString}
}
render() {
return (
<div id="pageContent" className="container" dangerouslySetInnerHTML={this.createMarkup()}></div>
);
}
It is inserting the string variable, but when you inspect it, the output is this: (you can see the outter div's className is now class, however the string that was inserted still is seen as className
Browser Inspector looking at the rendered code
<div id="pageContent" class="container"><div classname="test">TESTING</div></div>
Since the content passed through dangerouslySetInnerHTML is expected to an HTML and its not parsed by React and hence the className attribute isn't parsed to class, The content must follow the HTML convention of adding attributes must look like
createMarkup(){
var htmlString = '<div class="test">TESTING</div>';
return {__html : htmlString}
}
render() {
return (
<div id="pageContent" className="container" dangerouslySetInnerHTML={this.createMarkup()}></div>
);
}
However you could rather write it like
createMarkup(){
return <div className="test">TESTING</div>
}
render() {
return (
<div id="pageContent" className="container">{this.createMarkup()}</div>
);
}
So maybe I'm a year or two late but, I suspect that dangerouslySetInnerHTML expects not a JSX string but instead, a HTML String.
class App extends React.Component {
createMarkup() {
var htmlString = '<div class="test">TESTING</div>'; // class instead of className
return { __html: htmlString };
}
render() {
return (
<div
id="pageContent"
className="container"
dangerouslySetInnerHTML={this.createMarkup()}
/>
);
}
}
let main = document.getElementById("main");
ReactDOM.render(<App />, main);
console.log("The innerHTML of `#main` is:")
console.log(main.innerHTML)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="main"></div>
`innerJSX` instead of `innerHTML`
And if you absolutely have to set innerJSX which you appear not to, you can do so using babel, but different ways depending on whether you're using node or browser js.
NodeJS: You'll need #babel/core and #babel/plugin-transform-react-jsx for this and React with webpack will support this.
let parseJSX = (function() {
let babel = require("#babel/core");
return function(str) {
let code = babel.transformSync(str, {
plugins: ["#babel/plugin-transform-react-jsx"]
}).code;
return eval(code);
}
})()
Browser: This refers to in-browser only ReactJS. You'll also need babel for this.
// Assuming babel is already loaded.
function parseJSX(str) {
return eval(
Babel.transform(str,
{
presets: [],
plugins: ["transform-react-jsx"]
}
).code
)
}
Testing
Browser
// Browser Version (Babel is loaded)
function parseJSX(str) {
return eval(
Babel.transform(str,
{
presets: [],
plugins: ["transform-react-jsx"]
}
).code
)
}
class App extends React.Component {
createMarkup() {
var jsxString = '<div className="test">TESTING</div>'; // className as in JSX
return parseJSX(jsxString);
}
render() {
return (
<div
id="pageContent"
className="container"
>
{this.createMarkup()}
</div>
);
}
}
let main = document.getElementById("main");
ReactDOM.render(<App />, main);
console.log("The innerHTML of `#main` is:")
console.log(main.innerHTML)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="main"></div>

Pull data from IndexedDB into array and output it via ReactJS

My actual Javascript code is the following:
var schoolsData = new Array();
myDB.schools
.each(function(school) {
console.log('"' + school.title + '" wird auf den Array gepusht.');
schoolsData.push(new Array(school.title, schools.schoolnumber, school.address, school.principal, school.email, school.creationdate, school.lastupdate, school.comment));
});
var SchoolsRender = React.createClass({
render: function() {
return (
<tr>
{this.props.list.map(function(listValue){
return <td>{listValue}</td>;
})}
</tr>
)
}
});
ReactDOM.render(<SchoolsRender list={schoolsData} />, document.getElementById('schoolsDATA'));
As you can see I am trying to pull data from my local IndexedDB database (I am using dexieJS) and put it via ReactJS into a table element but nothing appears. Where is the point?
Edit: I think the problem is basically that I'm trying to output that 3D array. Is there any simple and elegant solution?
Add another component RowRender to render single row. Modify SchoolsRender component accordingly.
var RowRender = React.createClass({
render: function() {
return (
<tr>
<td>{this.props.title}</td>
<td>{this.props.schoolnumber}</td>
<td>{this.props.address}</td>
<td>{this.props.principal}</td>
</tr>
)
}
});
var SchoolsRender = React.createClass({
render: function() {
return (
<table>
{this.props.list.map(function(listValue,index){
return <RowRender key={index} title={listValue.title} schoolnumber={listValue.schoolnumber} address={listValue.address} title={listValue.address} />;
})}
</table>
)
}
});

React.js Namespaced Components show nothing

In the official document React.js, there is a new feature:Namespaced Components from version 0.11.
REF:http://facebook.github.io/react/docs/jsx-in-depth.html
var Form = MyFormComponent;
var App = (
<Form>
<Form.Row>
<Form.Label />
<Form.Input />
</Form.Row>
</Form>
);
var MyFormComponent = React.createClass({ ... });
MyFormComponent.Row = React.createClass({ ... });
MyFormComponent.Label = React.createClass({ ... });
MyFormComponent.Input = React.createClass({ ... });
So, I refer it and write following code to create a component
var MysearchPage=React.createClass({
render:function(){
return (
<div>
</div>
);
}
});
MysearchPage.Title=React.createClass({
render:function(){
return (
<h1>MysearchPage!</h1>
);
}
});
MysearchPage.Search= React.createClass({
render:function(){
return (
<div>
{this.props.searchType}:<input type="text"/>
<button>Search</button>
</div>
);
}
});
var SearchPage=MysearchPage;
var App=(
<SearchPage>
<SearchPage.Title />
<SearchPage.Search searchType="Content"/>
</SearchPage>
);
React.render(
App,
document.getElementById('nuno')
);
Finally,there is no error message,but it show nothing and I cannot see result.I want to know why it show nothing and where is error.
I guess "SearchPage.Title" node do not append to "SearchPage".
Because I change code:
var App=(
<div>
<SearchPage.Title />
<SearchPage.Search searchType="Content"/>
</div>
);
Perhaps, it can get result.
So,I have another problem.
var MysearchPage=React.createClass({
render:function(){
return (
<div>
</div>
);
}
});
What is the difference between the above code and pure HTML tag ? Thank you!
The render function of Mysearchpage just returns an empty div, so you'll have to explicitly render all its component children:
render:function(){
return (
<div>
{this.props.children}
</div>
);
See https://facebook.github.io/react/docs/multiple-components.html

How do I handle complex objects in ReactJS?

I have the following ReactJS code :
var data1 = {"Columns":["Title1","Title2","Title3"],"Rows":[{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]},{"CellText":["Cell0","Cell1","Cell2"]}]};
var GridRow = React.createClass({
render: function() {
if(this.props.data){
}
return (
<div>Text</div>
);
}
});
var GridList = React.createClass({
render: function() {
if(this.props.data){
var Header = this.props.data.Columns.map(function (columns) {
return (
<GridRow data={columns}>
);
});
var Row = this.props.data.Rows.map(function (rows) {
return (
<GridRow data={rows}>
);
});
}
return (
<ul>
<li>{Header}</li>
<li>{Row}</li>
</ul>
);
}
});
var GridBox = React.createClass({
render: function(){
return (
<GridList data={data1} />
);
}
});
I'm trying to pass the data1 variable to the GridList where it is split up to Columns (for header) and rows. The problem is that I get the following exception at runtime:
In file "~/Scripts/Grid.jsx": Parse Error: Line 30: Unexpected token
return (at line 30 column 6) Line: 52 Column:3
I'm running this from within Visual Studio 2013 with ReactJS.
The stated Line nr and colum makes no sense
Im trying to render a table based on metadata(columns) and row data from service.
You need to close tags either with a matching closing tag, or using self closing tags.
// ERROR
<GridRow data={rows}>
// OK
<GridRow data={rows}></GridRow>
// Best
<GridRow data={rows} />
The error message isn't very helpful.
Also, when creating an array of nodes, it's good to give them keys.
Rows.map(function(row, i){
return <GridRow data={rows} key={i} />;
});
I played around with it some more, and the weirdness comes from JSX accepting anything between an opening tag and <, {, or } as raw text. If you did something like this:
var GridList = React.createClass({
render: function() {
if(this.props.data){
var Header = this.props.data.Columns.map(function (columns) {
return (
<GridRow data={columns}>
);
});
var Row = this.props.data.Rows.map(function (rows) </GridRow>
)});
}
return (
<ul>
<li>{Header}</li>
<li>{Row}</li>
</ul>
);
}
});
It'll happily output this:
var GridList = React.createClass({displayName: "GridList",
render: function() {
if(this.props.data){
var Header = this.props.data.Columns.map(function (columns) {
return (
React.createElement(GridRow, {data: columns},
");" + ' ' +
"});" + ' ' +
"var Row = this.props.data.Rows.map(function (rows) ")
)});
}
return (
React.createElement("ul", null,
React.createElement("li", null, Header),
React.createElement("li", null, Row)
)
);
}
});
It's completely content until it encounters the { after Rows.map(function (rows), which means "go back into JavaScript expression mode", and it encounters a return in an expression, which is invalid, so it bails, and gives the best error it can.

Categories