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

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();

Related

JSX add attribute to array of different objects

I have a page with a bunch of sub-pages:
render(){
let elements = [<Apple>,<Orange>,<Pear>];
return <div>
{Elements}
</div>
}
I want to give each of these elements the same property, e.g. color:
render(){
let elements = [<Apple>,<Orange>,<Pear>];
elements.forEach(i=>i.setAttribute('color','blue')); //???
return <div>
{Elements}
</div>
}
So that it would be equivalent to:
render(){
return <div>
<Apple color='blue'/>
<Orange color='blue'/>
<Pear color='blue'/>
</div>
}
How would I do this?
Fix your elements to
let elements = [Apple, Orange, Pear];
then use array map to pass a common prop.
render() {
let elements = [Apple, Orange, Pear];
const elementsWithColorBlue = elements.map((Element) => (
<Element color="blue" />
));
return <div>{elementsWithColorBlue}</div>
}
An alternate way of writing than the answer above would be as below
render(){
return (
<div>
{[Apple, Orange, Pear].map(Element => <Element color="blue" />)}
</div>
)
}

How can I declare a variable inside brackets?

I have a render function like this one:
render() {
const statement = true
return (
<div>
{
statement &&
<div>
<p>
{this.buildStuff()}
</p>
<p>
{this.buildStuff()}
</p>
<p>
{this.buildStuff()}
</p>
</div>
}
</div>
);
}
To avoid calling buildStuff() three times, I would like to assign it to a variable. How can I declare a variable after the line with statement &&?
A quick solution would be to do
const statement = true
const stuff = statement ? buildStuff() : null;
but this solution use two branches instead of one.
You can try this code on StackBlitz.
This what it would look like in Razor.
You can try something like this as well:
You can create a function that deals with this UI representation.
In this function, you can call buildStuff and have it return 3 <p> tags.
Then in main render, you can check your condition and render accordingly. This will make your render clean and declarative.
getBuildJSX() {
const stuff = this.buildStuff();
return Array.from({ length: 3}, () => <p> { stuff }</p>);
}
render() {
const statement = true
return (
<div>
{
statement ? this.getBuilsJSX() : null
}
</div>
);
}
Try it online
First solution (edit: alternative)
render() {
const statement = true;
const stuff = this.buildStuff(statement, 3); // jsx result looped in divs
return (
<div>
{
statement &&
<div>
{ stuff }
</div>
}
</div>
);
}
Alternative, memoization (caching of functions) if this is your goal:
const memoize = require('fast-memoize');
const memoized = memoize(this.buildStuff);
...
render() {
const statement = true;
return (
<div>
{
statement &&
<div>
<p>
{memoized()}
</p>
<p>
{memoized()}
</p>
<p>
{memoized()}
</p>
</div>
}
</div>
);
}
The true power of memoization however is, if you cache based on the parameter you give to buildStuff (maybe you move statement into buildstuff?). In your case I would just clean up the component and parameters in favour of readability rather than optimising something. So last alternative:
// Stuff is a component now
const Stuff = ({statement, stuff}) => {
if(!statement)
return null;
const result = stuff();
return (
<div>
<p>
{result}
</p>
<p>
{result}
</p>
<p>
{result}
</p>
</div>
)
}
render() {
return (
<div>
<Stuff statement={true} stuff={this.buildStuff} />
</div>
);
}
The benefit, you can now choose to pass the result or the function itself through props, and in the downward component either call the function or simply have its results passed through.
Single answer to your question in the headline: you cant, JSX is not a templating engine like Razor.
Explanation:
// JSX
<div id="foo">Hello world</div>
// Translates into
React.createElement("div", {id: "foo"}, "Hello world");
// JSX
<div>{ statement && <div /> }</div>
// Translates to
React.createElement("div", null, statement && React.createElement("div"));
Either you declare a new variable with an attribute, or you simply cant, since javascript does not allow variable creation inside parameters of functions.
I think one of the main ideas of react is to use components to structure your code.
So one way to do it would be like this:
render() {
const statement = true;
const Stuff = ({statement}) => {
if (!statement) { return null; }
return this.buildStuff();
}
return (
<div>
<p>
<Stuff statement={statement} />
</p>
<p>
<Stuff statement={statement} />
</p>
<p>
<Stuff statement={statement} />
</p>
</div>
);
}
Updated StackBlitz.
This answer is an answer to the problem but not a solution to the question. If you cannot declare a variable inside brackets in react (as you could do in Razor for example). Calling twice a statement can still be your best bet.
render() {
const statement = true
const stuff = statement ? this.buildStuff() : null
return (
<div>
{
statement &&
<div>
<p>
{stuff}
</p>
<p>
{stuff}
</p>
<p>
{stuff}
</p>
</div>
}
</div>
);
}
At least, we call this.buildStuff() only if needed and if we do, we call it only once.

How to get value from contentEditable in reactjs

I'm fairly new to ReactJS. I am looking to get the value inside a <div> when contentEditable is set to true.
const listResults = this.state.results['1'].map((result) =>
<div key={result.toString()} contentEditable="true">
{result}
</div>
);
return (
<h1> listResults </h1>
<div> {listResults} </div>
)
I am currently outputting a list into pre-filled text-boxes which allows the user to edit them. I am looking to add in a button which once clicked captures the data inside all of the text-boxes. Can anyone point me in a direction on how to capture the changed data.
It may also be worth noting I am using ReactJS on the client side through a CDN.
To get value of editable div:
class App extends React.Component {
constructor(){
super();
this.state = {
arr: [1,2,3,4,5]
}
this.change = this.change.bind(this);
}
change(e, index){
let tmpArr = this.state.arr;
tmpArr[index] = e.target.textContent;
this.setState({arr: tmpArr})
}
render(){
console.log(this.state);
return (
<tr>
{this.state.arr.map((el, index) => <td key={index} id="test" onBlur={(e) => this.change(e, index)} contentEditable="true">{el}</td>)}
</tr>
);
}
}
https://jsfiddle.net/69z2wepo/84647/
One note, you can't return two elements on the same level:
return (
<h1> listResults </h1>
<div> {listResults} </div>
)
It should be wrapped like this:
return (
<div>
<h1> listResults </h1>
<div> {listResults} </div>
</div>
)

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

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

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')
);

Categories