How to separate items from array? - javascript

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)

Related

Access Individual Elements in an Array from an API (react)

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.

in react when I remove a dynamic input, the input does not show the right value on the browser

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.

How I can number of the same elements in array?

I'm making Shopping Cart, and I need to show all elements which were added to Shopping Cart, but elements which are the same should appear in the list only 1 time , but in this case i need to show quantity of these elements...
{shoppingCart.map((book) => (
<div key={book.id} className="book-element">
<div className="col-1">
<img src={book.image}/>
</div>
<div className="col-4 shp-description">
<p>{book.title}</p>
<p>Cover: {book.hardCover === false ? 'Paperback' : 'Hardcover'}</p>
</div>
<div className="col-2">{}</div> // here i need to set quantity of the same elements
<div className="col-2">{book.price}$</div>
<div className="col-1">
<i className="fa fa-times" aria-hidden="true"></i>
</div>
</div>
))}
as #epascarello says, you need to process your list before mapping it to react components
processBookList(shoppingCart).map((book) => ...)
and then you have something like this
function processBookList(bookList) {
// iterate over your list of books and build a new array
// or maybe use array.reduce if it suits you
return proccessedBookList;
}
So process the books, basic task of combining records
getCartData() {
// loop over the cart
const combined = this.shoppingCart.reduce((obj, book) => {
// reference the book we already have or create a new record
obj[book.id] = obj[book.id] || { ...book, qty: 0 };
// increase the qty
obj[book.id].qty++;
return obj;
});
// return the array of books with qty
return Object.values(combined);
}

react render data array map

I have facing an issue in react js, i use array map function to render data on component but they show last value of data.
react component
if (this.state.data
&& this.state.data.length
)
{this.state.data.map(({ full_name }, i) => (
name = (
<p key={i}>{this.state.data[i].full_name }</p>
)))
}
return (
<div className="row">
{names}
</div>
show all values of data but they show last value
names data
alex
john
smith //they show last value
what should i change in my code?
anyone help me?
Try this :
const names =
this.state.data.length > 0 &&
this.state.data.map(name => <p key={name}>{name}</p>);
return (
<div className="row">
{names}
</div>
);
edited based on comment feedback below
const names = this.state.data.map((item) => (
<p key={item}>{item.full_name }</p>
))
or
const names = this.state.data.map(({full_name}) => (
<p key={full_name}>{full_name}</p>
))
here's a sandbox example
https://codesandbox.io/s/nostalgic-wood-9jrib?file=/src/App.js

How to access index of nested items in JS object?

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

Categories

Resources