This is where I should probably add something to fix the issue, I am stuck with this index that returns the whole object, my goal is to print the index of clicked item, please someone help
const listItems = this.state.list.map((item, index) =>
Object.values(item).map(nestedItem => (
<div>
<Card.Header>
{nestedItem.title}
</Card.Header>
<div class="ui buttons fluid">
<button
onClick={() => this.upvote(index)}
>
UPVOTE
</button>
</div>
))
);
The code below is working correctly it's just that I hard coded the index I am looking for 2 in this example
console.log(Object.keys(this.state.list[index])[2]);
And this is the whole object, all I need now is the index of it
0: "-LORYsI9mLP8mu_2BTKS"
1: "-LORZVOq8SMUgTOPgpXK"
2: "-LORZtqZeg3nyOW4p9I1"
3: "-LOYbElg81jbPtao2nl4"
4: "-LOZ3pNNMAOtNxMWNDi4"
Do you just need the index of the inner mapping? I'm confused by the question still, but perhaps something like this.
const listItems = this.state.list.map((item, index) =>
Object.values(item).map((nestedItem, nestedIndex) => (
<div>
<Card.Header>
{nestedItem.title}
</Card.Header>
<div class="ui buttons fluid">
<button
onClick={() => this.upvote(index, nestedIndex)}
>
UPVOTE
</button>
</div>
))
);
If this doesn't work, could you post an example of your data structure?
here are the docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Syntax
If you want the indices for the nested items, the you'll need to have another variable in the map fn
Object.values(item).map((nestedItem, nestedIndex) => <div>...</div>
and then use the nestedIndex variable in your upvote method
Related
Ok, so I have a very strange problem (I'm using next.js).
I'm mapping shuffled array.
const otherPoepleData = shuffle(allPeople).filter(item => item.full_slug !== data.full_slug).slice(0, 3)
{otherPoepleData.map((item, index) =>
<SpeakerNew data={item} key={item.id} index={index} />
)}
To sum up the problem I've put inside SpeakerNew component following code:
<div style={{ backgroundImage: `url(${image.filename})` }}>
{image.filename}
</div>
And here are the results:
<div style="background-image:
url(https://something.com/blablaba57674676343zzx.png);">
https://something.com/blablaba13123123dasdzz.png
</div>
The content of the div is 100% correct, however the backgroundImage url is incorrect. Taken from completely other person from array I'm mapping. What coulde be the problem here?
I am a beginner and I am trying to create a recipe app. I managed to set up an API that gives an Array of 10 objects each time I search for a meal like so.
I access the elements of each recipe using a map
{recipes.map(recipe =>(
<RecipeCard
key={recipe.recipe.label}
title ={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
/>
))}
Here is also my Const Recipe Card just for some more context. It functions fine.
const RecipeCard = ({title, calories, image, ingredients}) => {
const round = Math.round(calories);
return(
<div className = {style.recipe}>
<h1 >{title}</h1>
<ol className = {style.list}>
{ingredients.map(ingredient => (
<li>{ingredient.text}</li>
))}
</ol>
<p>calories: {round} </p>
<img className = {style.image} src={image} alt=""/>
<button>Add to Favorites</button>
</div>
)
}
I currently only want to access the information from the first array, but whenever I change recipes.map to recipes[0] it says that function does not exist. How should I go about accessing individual elements from the arrays provided from the API?
You can use .slice(0, 1) to create a shallow copy (a new array with just first element):
{recipes.slice(0, 1).map(recipe =>(
<RecipeCard
key={recipe.recipe.label}
title ={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
/>
))}
Or use destructuring:
const [recipe] = recipes // before "return"
// ....
<RecipeCard
key={recipe.recipe.label}
title ={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
/>
Or use index:
<RecipeCard
key={recipes[0]?.recipe.label}
title ={recipes[0]?.recipe.label}
calories={recipes[0]?.recipe.calories}
image={recipes[0]?.recipe.image}
ingredients={recipes[0]?.recipe.ingredients}
/>
The ?. is called optional chaining, you can use it to avoid error like Can't Read property of undefined, i.e. when the first element is undefined and you try to read its properties.
I'm new in React and i'm learning to use it with hooks.
I tried to put dynamics inputs which works so far but I have a display problem.
If I delete the last input, no problem but if I delete others inputs than the last one then the correct values does not show on the browser.
For example I add 2 inputs.
first one titled "one" and second titled "two".
If I delete "one", the remain input on screen shows "one" or it should show "two".
However, in the array where I collect the inputs infos, there is the correct remaining input.
(see screenshot).
How can I do to show the correct title in the input on the browser ?
const [titleSelected, setTitleSelected] = useState(true);
const [questionType, setQuestionType] = useState([]);
const [questionsTitle, setQuestionsTitle] = useState([]);
{questionType ? (
questionType.map((questions, index) => {
return (
<div key={index} className="questions">
<div className={questions === "texte" ? "orange" : "red"}>
<span>{questions === "texte" ? "1" : "2"}</span>
<img src={Minus} alt="" />
<img
src={questions === "texte" ? FileWhite : StarWhite}
alt=""
/>
</div>
<input
type="text"
placeholder="Ecrivez votre question"
onChange={(event) => {
let tab = [...questionsTitle];
// si index de l'objet existe on update index de l'objet par index sinon on push le nouvel objet
let tabIndex = tab.findIndex(
(element) => element.index === index
);
if (tabIndex !== -1) {
tab[tabIndex].type = questionType[index];
tab[tabIndex].title = event.target.value;
} else {
tab.push({
index: index,
type: questionType[index],
title: event.target.value,
});
}
setQuestionsTitle(tab);
}}
></input>
<div>
<img src={ChevronUp} alt="move up" />
<img src={ChevronDown} alt="move down" />
<img
src={SmallTrash}
alt="delete question"
onClick={() => {
let tab = [...questionType];
tab.splice(index, 1);
setQuestionType(tab);
let tabTitle = [...questionsTitle];
tabTitle.splice(index, 1);
setQuestionsTitle(tabTitle);
}}
/>
</div>
</div>
);
})
) : (
<div></div>
)}
<div className="questionType">
<div
className="addText"
onClick={() => {
let tab = [...questionType];
tab.push("texte");
setQuestionType(tab);
}}
>
<img src={File} alt="" />
<p>Ajouter une question "Texte"</p>
</div>
<div
className="addNote"
onClick={() => {
let tab = [...questionType];
tab.push("note");
setQuestionType(tab);
}}
>
<img src={Star} alt="" />
<p>Ajouter une question "Note"</p>
</div>
</div>
screenshot
Issues
You are mutating the array you are mapping so don't use the array index as the react key. If you remove the ith element all the elements shift up, but the keys remain unchanged and react bails on rerendering.
Lists & Keys
questionType.map((questions, index) => (
<div key={index} className="questions">
...
</div>
)
The array index as a React key doesn't "stick" to the element object it "identifies".
You've also some state object mutation occurring.
tab[tabIndex].type = questionType[index];
tab[tabIndex].title = event.target.value;
This is masked by the shallow copy let tab = [...questionsTitle];.
Solution
Select a react key that is unique among siblings and related to the elements, like an id.
Since you enclose the index when adding new elements to the array I think you can resolve the key issue by simply using the saved index.
questionType.map((questions, index) => (
<div key={questionsTitle[index].index} className="questions">
...
</div>
)
This may be a little confusing so I suggest changing the property to id.
questionType.map((questions, index) => (
<div key={questionsTitle[index].id} className="questions">
...
<input
...
onChange={event => {
...
tab.push({
id: index,
type: questionType[index],
title: event.target.value,
});
...
}}
/>
...
</div>
)
A further suggestion is to avoid using the array index at all. The following code can quickly get out of sync when the array index being mapped doesn't align to the saved index in the element.
let tabIndex = tab.findIndex(element => element.index === index);
Generate id's for your elements and use that to determine if elements should be updated or appended. When updating make sure to shallow copy the array and then also shallow copy the element object being updated.
I'm making weather app for 7 days and I need to create abillity for users to open some of days to see more information about weather of current day. So, it means that every item choosen by user has to contain unique id (i don't know could I use in this situation index instead of id) to show information only about some of day. So before this I had some code:
const DailyWeatherData = ({dailyData, isLoading}) => {
const getWeatherStatistic = (value0,value1) => {
if(dailyData && Array.isArray(dailyData.daily)){
return (
<div className="col-lg-3 box-daily-weather">
<NavLink to={'/WeatherDayStat'}>
{setDay([value1])}
<div className="temp-day">{Math.ceil(dailyData.daily[value0].temp.day)}°C</div>
<div className="feels-like">Feels like: {Math.ceil(dailyData.daily[value0].feels_like.day)}°C</div>
<div className="daily-weather-condition">Conditions: {dailyData.daily[value0].weather.map(e => e.main)}</div>
</NavLink>
</div>
)
}else {
return isLoading === true ? <Preloader /> : null
}
}
const setDay = (param) => {
return checkCod ? null : setCurrentDate(new Date(),param)
}
return (
<div>
<div className="daily-weather-container">
{checkCod ? null : <div className="daily-title">Daily Weather</div>}
<div className='row scrolling-wrapper justify-content-center'>
{getWeatherStatistic(1,1)}
{getWeatherStatistic(2,2)}
{getWeatherStatistic(3,3)}
{getWeatherStatistic(4,4)}
{getWeatherStatistic(5,5)}
{getWeatherStatistic(6,6)}
</div>
</div>
</div>
)
}
export default DailyWeatherData
In function getWeatherStatistic you can see 2 arguments, value0 - doesn't matter here, value1 - using to show only 1st-6 object, because array which i have got from ajax request contains more days(10) but I need to show only 6 of them. And most importantly, each of them is separate. Logically I'd use map, but It shows all items, so I can use slice but it also shows 6 items in 1 column.
The next problem, this array has not contain parameter like ID, that's why I can't add to NavLink id. If there were ID, I would make something like that dailyData.daily.map(p => <NavLink to={'/WeatherDayStat' + p.id}>)
Also, just in case, add the state code (daily - array which I need):
So I have 2 questions:
How to show only 6 days from array?
How to add unique ID to every Item from array?
Making something like this:
//making new array with data I need
let sliceDailyData = dailyData.daily ? dailyData.daily.slice(1,7) : null
//using map with new array
{sliceDailyData ? sliceDailyData.map((i) => <div key={i.dt} className="col-lg-3 box-daily-weather">
{getCurrentDate(new Date())}
<NavLink to={'/WeatherDayStat'}>
<div className="temp-day">{Math.ceil(i.temp.day)}°C</div>
<div className="feels-like">Feels like: {Math.ceil(i.feels_like.day)} °C</div>
<div className="daily-weather-condition">Conditions: {i.weather.map(i => i.main)} </div>
</NavLink>
</div>
): null}
Speaking about ID, I have created variable which generte id and push it to array.
You can store your dailyData.daily array in an object and then retrieve it with key, you can use something simple but SEO friendly like obj['day'+(dailyData.daily.indexOf(d)+1)]
obj{}
dailyData.daily.forEach(d=>array.indexOf(d)<=5?obj[String(Math.random())]=d:null)
I would like to use a map to display the ith value and the i+1th value inside a javascript map to display a set of two cards inside a carousel.
The following is the code I am using, which I would like to modify to get the desired result:
{testimonialContent.map((testimonial, i) => {
return (
<Carousel.Item className={classes.carousel_item}>
<div className={classes.root}>
<div className={classes.testimonial_card}>
{testimonial[i]}
</div>
{/* Second card */}
<div className={classes.second_card}>
{testimonial[i+1]}
</div>
</div>
</Carousel.Item>
Any help or suggestion is appreciated. Thanks.
You can use reduce() to combine data.
NOTE: (index % 2 === 0) is where you specify your nth child (eg: 2 in this case)
Later in your render method use destructuring in map().
const sampleData = ['first', 'second', 'third', 'fourth', 'fifth']
class App extends React.Component {
render() {
console.log("rendered");
const edited = [].concat(sampleData).reduce((unique, value, index) => {
if (index % 2 === 0) {
return [...unique, [value]];
}
unique[unique.length - 1].push(value);
return unique;
}, [])
return (
<div>
{edited.map(([item1, item2]) =>
<div className='block'>
{item1 && <div className='odd'>{item1}</div>}
{item2 && <div className='even'>{item2}</div>}
</div>
)}
</div>
);
}
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
.block {
border: 1px solid gray;
}
.odd {
color: red;
}
.even {
color: blue;
}
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
use the entire array not the current iteration
Testimonial in each iteration of the map is a single object. Whereas testimonialContent is the entire array.
{testimonialContent.map((testimonial, i) => {
return (
<Carousel.Item className={classes.carousel_item}>
<div className={classes.root}>
<div className={classes.testimonial_card}>
{testimonial[i]}
</div>
{/* Second card */}
<div className={classes.second_card}>
{testimonialContent[i+1]} // this is the line to change
</div>
</div>
</Carousel.Item>
But something feels very off here. I think you might have an x y problem
Why would you want to use the next iteration as the current iteration? The last item will fail because it doesn't exist and the value of the first testimonialContent will never be shown because you're always starting from index 1.
I would rethink what you're doing here and maybe take another approach.
testimonial is not an array, but the current iterated item in that array. For the "next" item you can use the array testimonialContent.
From the comment I learn that you want to actually produce n/2 rows, so that each item only occurs once. In that case using a plain .map() is not good as it will generate as many rows, and you only need half that number of rows. Instead, you could generate an array with half the number of rows (rounded upwards) with Array.from and use the callback argument of that method.
Array.from({length: (testimonialContent.length+1)>>1}, (_, i) => {
return (
<Carousel.Item className={classes.carousel_item}>
<div className={classes.root}>
<div className={classes.testimonial_card}>
{testimonialContent[i*2]}
</div>
{/* Second card */}
<div className={classes.second_card}>
{testimonialContent[i*2+1] || ""}
</div>
</div>
</Carousel.Item>
)
})
Refer to the testimonial instance in your first div and to the element on the i-th +1 palce in your testimonialContent array in your seccond div.
{testimonialContent.map((testimonial, i) => {
return (
<Carousel.Item className={classes.carousel_item}>
<div className={classes.root}>
<div className={classes.testimonial_card}>
{testimonial}
</div>
{/* Second card */}
<div className={classes.second_card}>
{testimonialContent[i+1]}
</div>
</div>
</Carousel.Item>