can't find variable: x - looping through an array in ReactJS - 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] }.

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>
)}

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

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>
)
}

Mapping Double nested JSON - Object not allowed in React Child

I have a json file that looks like this:
"skills":[
{
"type":"Languages",
"skill":[
{
"name":"Python"
},
{
"name":"Java"
},
{
"name":"JavaScript"
},
{
"name":"HTML"
},
{
"name":"Bash"
},
{
"name":"MySQL"
}
]
},
{
"type": "Flavours",
"skill": [
{
"name":"Reactjs"
},
{
"name":"Angularjs"
},
{
"name":"Agile"
},
{
"name":"Waterfall"
},
{
"name":"Kanban"
}
]
},
{
"type": "Technologies",
"skill": [
{
"name":"Jira"
},
{
"name":" BitBucket"
},
{
"name":"Git"
}
]
}
]
},
And i am trying to render it using a nested mapping function:
var skills = this.props.data.skills.map((skills) =>{
var skill = skills.skill.map(function(skill){
return <li key={skill.name}>{skill}</li>
})
return <ul key={skills.type}>{skills}</ul>
})
However it says "Error: Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead."
So i tried it like this:
var skills = this.props.data.skills.map(function(skills){
var skillsArr = []
var skill = skills.skill.map(function(skill){
var skillArr = []
skillArr.push(<li key={skill.name}>{skill}</li>)
return <span>{skillArr}</span>
})
skillsArr.push(<div key={skills.type}><h3>{skills.type}</h3>
<ul>
{skill}
</ul>
</div>);
return <div>{skillsArr}</div>
})
But this too gives me the exact same error, i dont get what is wrong here because if i do a single mapping of just the skill types it works, it is only when i try to render the inner mapped items does this error occur and break my code
This is how i am calling it btw:
<div className="bars">
<ul className="skills">
{skills}
</ul>
</div>
If we are talking about using React, you should think more about how to organize your code in order to follow a proper component structure, that will let clear what you want to render and how to properly split your data and responsibilities.
Looking to your JSON, we have a set of "skills" that have skills inside it (let's call them "innerSkills").
We can easily split it into 3 components, let's think together:
We can have a List that will render all your Skills.
We can have a Skill that will be responsible for rendering each Skill data, inside it, we will need to render the InnerSkills, so let's split it to another component.
We have then InnerSkill, that will be responsible for rendering each innerSkill that we have for each skill.
So, long story short, what we have is:
List -> Skill -> InnerSkills
Great, now that we established the split, let's see how we can make each component responsible for rendering its data.
Let's say we want to simply call <List skills={data} />. Following this, we can then start on the list itself, which would look something like:
const List = ({ skills }) => (
<ul>
{skills.map((skill, i) => (
<Skill key={i} skill={skill} />
))}
</ul>
);
Now that we are looping through all Skills and calling the Skill component for rendering it, we can take a look at how Skill should look, since it will also need to loop through skill.
const Skill = ({ skill }) => (
<li>
<p>Type: {skill.type}</p>
<ul>
{skill.skill.map((innerSkill, i) => (
<InnerSkill key={i} innerSkill={innerSkill} />
))}
</ul>
</li>
);
Great. Now we already have the two loops you need to render all the data, so it's just missing the definition on how each InnerSkill should look like, and we can take a simplified approach and say we just want to render the name, so it could be something like:
const InnerSkill = ({ innerSkill }) => (
<li>
<p>Name: {innerSkill.name}</p>
</li>
);
To summarize this implementation, I made a simple code sandbox so you can See it live! and play around with the components.
I hope this clarifies your question and helps you to think better in the future on how you want to organize stuff, first check how to split, later how to render. Don't try to start rendering everything inside loops because it will get nasty.
There are two things in your code causing this error:
var skills = this.props.data.skills.map((skills) =>{
var skill = skills.skill.map(function(skill){
// should be <li key={skill.name}>{skill.name}</li>
return <li key={skill.name}>{skill}</li>
})
// should be <ul key={skills.type}>{skill}</ul>
return <ul key={skills.type}>{skills}</ul>
})
Assuming you want a single unordered list of all skill names, I'd suggest using the flatMap() function to re-write this as follows:
<div className="bars">
<ul className="skills">
{this.props.data.skills.flatMap((skillGroup) =>
skillGroup.skill.map((skill) => (
<li key={skill.name}>{skill.name}</li>
))
)}
</ul>
</div>

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

Reactjs - Need to bind a onClick handler twice?

Coming from Vue.js (two way data flow) I have question about react one way data flow - I have a Parent that have a handler for its child onClick:
<div className="recipe-container">
<button onClick={this.toggleRecipeList.bind(this)}>Show Recipes</button>
<RecipeList showRecipe={this.showRecipe} list={this.state.recipes} />
</div>
So, I pass showRecipe handler, which has only one parameter (and simply just logs it to the console).
My RecipeList looks like this (stateless func):
return (<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={props.showRecipe(rec)} key={key}>{rec.title}</li>
})
}
</ul>)
I tried to launch showRecipe(rec) to have the current rec object as argument. Although I recive what I want, the handler is being fired from a button which is a sibling of RecipeList.
I manage to get it working by adding onClick={props.showRecipe.bind(null,rec)} to li element, but I find it really dirty way to do so.
Am I missing something? I thought showRecipe(rec) would be enough to get what I wanted. Why showRecipe(rec) is being fired with this set to button?
I think that your second snippet has a classic error:
return (<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={props.showRecipe(rec)/*here*/} key={key}>{rec.title}</li>
})
}
</ul>)
You are assigning the result of calling showRecipe to the onClick parameter, not the function itself. The bind solutions works, but if you want to pass the parameter rec without using bind you need to wrap the call:
return (<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={()=>props.showRecipe(rec)} key={key}>{rec.title}</li>
})
}
</ul>)
You can use es2015 stage-0 syntax in order to write it like this:
class Blah extends Component {
onClick = (recipe) => e => this.props.showRecipe(recipe);
render() {
return (
<ul className='recipe-list-bottom'>
{
props.list.map((rec, key) => {
return <li onClick={onClick(rec)} key={key}>{rec.title}</li>
})
}
</ul>
)
}
}

Resources