Can't dynamically render reactjs elements using .map() - reactjs

I am trying to dynamically render out ingredient/qty/measure using .map() in reactjs I am following a few tutorials online but unable to properly implement the code in my own code.
Here is the error I am currently getting:
react-dom.development.js:86 Warning: Functions are not valid as a React child.
This may happen if you return a Component instead of <Component /> from render.
Or maybe you meant to call this function rather than return it.
Here is the data I am trying to map over:
recipeIngredients: Array(2)
0: {name: 'lemon', quantity: '100', measure: 'g'}
1: {name: 'butter', quantity: '5', measure: 'cups'}
Here is my code:
import './IngredientsList.css'
let ingredientArray
function mapIngredients() {
ingredientArray.map((item) => (
<div className="ingredient-element">{item}</div>
))
}
function IngredientsList(props) {
console.log(props)
ingredientArray = props.recipeIngredients
return <div className="ingredient-list">{mapIngredients}</div>
}
export default IngredientsList
Basically, trying to render out the following set of divs (recipeIngredients.name has an additional class):
<div className="ingredient-list">
<div className="ingredient-element">recipeIngredients.quantity</div>
<div className="ingredient-element">recipeIngredients.measure</div>
<div className="ingredient-element ingredient-name">recipeIngredients.name</div>
</div>
I notice that the () are missing from the IngredientList function - VSCode keeps deleting them when I save the code so I can't manually add them...

You forgot to invoke the function. Here you're trying to render the function itself:
return <div className="ingredient-list">{mapIngredients}</div>
Instead, invoke the function and render its result:
return <div className="ingredient-list">{mapIngredients()}</div>
Additionally, the function currently doesn't return anything. Add a return statement:
function mapIngredients() {
return ingredientArray.map((item) => (
<div className="ingredient-element">{item}</div>
))
}

I'm seeing two issues here. First, you're not invoking the function(as you said that vs code is not letting you do that). The second is item is an object here. Try this instead:-
function IngredientsList(props) {
console.log(props)
ingredientArray = props.recipeIngredients || [];
return (
<div className="ingredient-list">
{
ingredientArray.map(item => (
<div className="ingredient-element">{item.name}</div>
))
}
</div>
)
}

Related

Failing to map property values in React.js and Typescript

I'm quite new to React and Typescript. I do have an object that has property values as arrays.I can get the object's value through the below logic.
let cityObj = {
"Harare":[
{
"released_on":"2007-11-08T00:00:00",
"slug":"0985"
},
{
"released_on":"2007-11-08T00:00:00",
"slug":"2346"
}
],
"bulawayo":[
{
"released_on":"2007-11-08T00:00:00",
"slug":"9383"
}
]
}
Object.keys(cityObj).forEach(el =>{
console.log(cityObj[el]);
})
The output is as follows;
array(3)
array(1)
This is what i'm seeking to do in them jsx react return function. By i'm only getting the city name e.g Harare and Bulawayo after using the code below.
{Objects.keys(cityObj).map((city:any) =>
<div> {city}
cityObj[city].map((el:any) => <span>- {el.slug}</span>)
</div>
)}
What I really want is something like this:
Harare
-0985
-2345
Bulawayo
-9383
But in this case, I'm only getting city names and the city data is not showing.
seems you just forget to pass inside map to a react executable code block
{Objects.keys(cityObj).map((city:any) =>
<div> {city}
{cityObj[city].map((el:any) => <span>- {el.slug}</span>)}
</div>
)}

Add custom CSS class via variable to returned jsx

I've created a custom component which essentially returns html markup in order to display content based on the values passed to the component. Here's a simplified version for brevity:
interface ContainerProps {
position?: string;
content?: string;
class?: string;
}
const CardContainer: React.FC<ContainerProps> = ({ position = "right", content = "n/a", class = "" }) => {
if ( position.trim().toLowerCase() === "right" ) {
return <><div className="ion-float-right" >{content}</div><div className="clear-right"></div></>
} else if ( position.trim().toLowerCase() === "left" ) {
return <div className="ion-float-left">{content}</div>
} else {
return null
}
};
export default CardContainer;
This works great, but I now need to be able to pass a css class name to the component. However, I can't work out how to add the "class" prop to the returned html/jsx.
I tried various code such as below. However, in all cases the code was output as actual html rather than the value of the prop:
return <div className="ion-float-left" + {class}>{content}</div>
return <div className="ion-float-left {class}" >{content}</div>
return <div className="ion-float-left class">{content}</div>
I also tried a few other random things in desperation and these typically cause a compilation error. What is the best way to achieve the intended result eg:
return <div className="ion-float-left myClassNameHere">{content}</div>
its like inserting a string inside another or adding them together. You can use classname={"yourclasse" + theDynamicClass} or className={yourClass ${dynamicClass}} (inbetween ``)
return <div className=` ion-float-left ${class}``>{content}

react map is not rendering all the objects

i'm using map to render the values in the object, but i get only the first object value. following is my code for map
{appliedjobs.map((job,index) => {
return <ul>
<li>{job.jobid}</li>
<li>{job.candidatephoneno}</li>
</ul>
})}
below is the console output
appliedjob: Array(3)
0: {candidatephoneno: "9876543210", jobid: "SVkbFhb30U8Rqx4hNEcx"}
1: {candidatephoneno: "1111111111", jobid: "dj7Q77DHzjSbd7AW89Hq"}
2: {candidatephoneno: "9176837787", jobid: "xtzIqohdx6hekXCiQfhO"}
Would need more code context to say for sure but you are referencing appliedjobs in the code and appliedjob in your console. You may also want to wrap the return in ()
Either use a function to render the ul component or directly return the elements.
render () {
// [...]
return (
{appliedjobs.map((job, index) =>
<ul key={index.toString()}>
<li>{job.jobid}</li>
<li>{job.candidatephoneno}</li>
</ul>
}
)
}
See: https://reactjs.org/docs/lists-and-keys.html

can't find variable: x - looping through an array in ReactJS

I'm trying to iterate through an array stored in the store.
I get this red box error: can't find variable: city.
Is this a correct way to loop through an array in reactJS?
class CitiesPage extends Component {
render() {
return (
<View>
<Text>Cities Info:</Text>
<div>
{this.props.citiesArr}.map(function(city) {
<li key={city}>{city}</li>
});
</div>
</View>
);
}
}
My array inside the store looks like this:
const STORE_STATES = {
citiesArr: [
{city:'Rome', population:'34454'},
{city:'Paris', population:'45678'},
{city:'London', population:'2334'},
{city:'Milan', population:'23456'},
{city:'Amsterdam', population:'1234'},
{city:'Dublin', population: '234'},
{city:'Valencia', population: '2345'},
{city:'Ankara', population: '3456'}
]
};
{
this.props.citiesArr.map(function(city) {
<li key={city}>{city}</li>
})
}
// or ES6 arrow function
{this.props.citiesArr.map((city) => <li key={city}>{city}</li>)}
Instead of
{this.props.citiesArr}.map(function(city) {
<li key={city}>{city}</li>
});
In JSX (that code that looks like HTML but actually isn't), JavaScript has to be between { } and you misplaced the second one. Babel most likely transpiles your JSX into a code that does something totally different and causes the error. Check the transpiled source code if you're not 100% sure.
<div>
{
this.props.citiesArr.map((city) =>
<li key={city}>{city}</li>
);
}
</div>
Javascript is written inside jsx using { [your javascript code] }.

How to use parent function inside react's map function

I'm passing the following functions to the following component...
<Main css={this.props.css} select={this.selectedCSS.bind(this)} save={this.saveCSS.bind(this)} />
Then inside the Main component I am using these functions...
<h1>Select the stylesheet you wish to clean</h1>
{
this.props.css.map(function(style){
if (style) {
return (<div className="inputWrap"><input type="radio" name="style_name" onClick={this.props.select(style)}/><span></span><a key={style}>{style}</a></div>)
}
})
}
</div>
<button className="cleanBtn" onClick={this.props.save}>Clean!</button>
Notice in my map function, I am passing this.props.select(style). This is a function from the parent, and I am trying to pass to it a parameter. But when I do this, I get an error...
Error in event handler for runtime.onMessage: TypeError: Cannot read property 'props' of undefined
Every other function I pass works. I've already tested them. In fact, the code works, the only issue is when I try to pass a function inside map. What is the reason for this? How can I fix it?
I tried to add .bind(this) but it runs in an infinite loop when I do so.
The problem is that Array.prototype.map doesn't bind a this context unless explicitly told to.
this.props.css.map(function(style) {
...
}, this) // binding this explicitly
OR
this.props.css.map((style) => { // arrow function
...
})
OR
const self = this;
this.props.css.map((style) => {
... // access 'self.props.select'
})
I also see another problem with your code. Inside map you're doing this
if (style) {
return (
<div className="inputWrap">
<input type="radio" name="style_name" onClick={this.props.select(style)}/>
<span>something</span>
<a key={style}>{style}</a>
</div>
);
}
Here input element is expecting a function for its onClick, but you're actually evaluating the function by calling this.props.select(style) and passing its return value (if at all it returns something) to onClick. Instead you may need to do this:
this.props.css.map((style) => {
if (style) {
return (
<div className="inputWrap">
<input type="radio" name="style_name" onClick={() => this.props.select(style)}/>
<span>something</span>
<a key={style}>{style}</a>
</div>
);
}
})
In your mapping function, this does no longer point to the react component.
Bind the context manually to resolve this:
{
this.props.css.map((function(style) {
if (style) {
return (<div className="inputWrap"><input type="radio" name="style_name" onClick={this.props.select(style)}/><span></span><a key={style}>{style}</a></div>)
}
}).bind(this))
}
Alternatively, use an ES6 arrow function, which preserves the surrounding context:
{
this.props.css.map(style => {
if (style) {
return (<div className="inputWrap"><input type="radio" name="style_name" onClick={this.props.select(style)}/><span></span><a key={style}>{style}</a></div>)
}
})
}
You mentioned passing a parameter when calling a parent's function? As onClick wants a reference to a function (but realising that you need to pass a parameter), you could try the following:
onClick={() => { this.props.select(style) }}

Resources