div's background is different than it's content (same values passed) - javascript

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?

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.

React - Split on string not having any effect

I am trying to split a given text at each \n in order to put them on individual lines.
The problem is, in React, I am using the following code:
const details = property.details !== undefined
? property.details.split("\n").map((item, i) => {
return <p key={i}>{item}</p>;
})
: "";
but there is no splitting made whatsoever. The returned array is simply the whole string. I tried the same string in the console of the browser and it works there.
Also, the typeof property.details is string.
What am I missing?
My render function for this component is:
render() {
const property = this.state.property;
const details =
property.details !== undefined
? property.details.split(/\r?\n/).map((item, i) => {
return <p key={i}>{item}</p>;
})
: "";
return (
<Fragment>
{this.state.isLoading ? (
<div className="sweet-loading" style={{ marginTop: "120px" }}>
<BarLoader
sizeUnit={"px"}
css={override}
size={200}
color={"#123abc"}
loading={this.state.isLoading}
/>
</div>
) : (
<div className="container p-4" style={{ marginTop: "4rem" }}>
<div className="row align-items-center">
<div className="row display-inline p-3">
<h3>{property.title}</h3>
<h5 className="fontw-300">{property.zone}</h5>
<h1 className="mt-5 price-font-presentation">
{property.sale_type} -{" "}
<strong>{property.price.toLocaleString()} EUR</strong>
</h1>
</div>
<Carousel>
{property.images.map(image => (
<img key={image.id} src={image.image} />
))}
</Carousel>
<div className="row p-3">
<h3 className="border-bottom">Detalii</h3>
{details}
</div>
</div>
</div>
)}
</Fragment>
);
}
Maybe I should mention that the information is taken with a django_rest api. Maybe there is a problem with returning \n in a string from there.
It might happen because client OS uses different symbols for new lines. Try this, it's multi-platform:
const details = property.details !== undefined
? property.details.split(/\r?\n/)
: [];
EDIT:
typeof property.details is string because it's string. calling split on property.details returns array, but string remains to be string.
From your updated code sample I can see that you are basically rendering details, which results in array transforming to string back again but without line seperators.
Maybe you have to map it to paragraphs for example:
<h3 className="border-bottom">Detalii</h3>
{details.map(detail => <p>{detail}</p>)}
Also, try white-space: pre; css property as alternative
Have you tried this version:
const details = property.details !== undefined
? property.details.split('\r\n').map((item, i) =>
<p key={i}>{item}</p>;
)
: '';
(It's the extra \r)

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

Warning: flattenChildren(...): Encountered two children with the same key in reactjs

I'm using Tabs from Material UI where I'm displaying a List component filtered by the tab, please see the code of the Tabs in my Container Component:
<Tabs
className="DrawerTabs"
inkBarStyle={{ display: 'none' }}
>
<Tab label="Headline"
data-route="/headline"
onActive={this.handleActive}
className={this.isActive('Headline')}
>
<div>
<ModulesListContainer
filter="Headline"
/>
</div>
</Tab>
<Tab label="Body"
data-route="/body"
onActive={this.handleActive}
className={this.isActive('Body')}
>
<div>
<ModulesListContainer
filter="Body"
/>
</div>
</Tab>
<Tab
label="Other"
data-route="/other"
onActive={this.handleActive}
className={this.isActive('Other')}
>
<div>
<ModulesListContainer
filter="Other"
/>
</div>
</Tab>
</Tabs>
and the code of the ModuleList I placed in each of the tabs which is showing only items based on the filter passed from the Container Component:
const ModulesList = (props) => {
let ListItems = props.modulesProps.map(module => {
if (props.filter === module.category) {
return (
<ListItem
key={module.id}
className="ModulePreview"
>
{module.id} - {module.name} - {module.thumbnail}
<FontAwesome
name="plus-circle"
size="2x"
onClick={props.addModule.bind(this, module)}
className="AddModule"
/>
</ListItem>
)
}
})
return (
<div className="ModulesList">
<List>
{ListItems}
</List>
</div>
)
}
Even though I can see only the filtered items in each of the tabs (thus key is unique as each item is there only once) I'm still getting this warning:
Warning: flattenChildren(...): Encountered two children with the same
key, 1. Child keys must be unique; when two children share a key,
only the first child will be used.
Why is that?
Any help / ideas / tips would be highly appreciated.
Thanks a lot in advance! :)
Meaning of that line is module.id is not unique, there will be 2 objects in array that have the same id=1, to avoid that you can use index of object, it will always be unique.
Use this:
let ListItemsUI = [];
props.modulesProps.forEach((module, i) => {
if (props.filter === module.category) {
ListItemsUI.push (
<ListItem
key={i}
className="ModulePreview"
>
{module.id} - {module.name} - {module.thumbnail}
<FontAwesome
name="plus-circle"
size="2x"
onClick={props.addModule.bind(this, module)}
className="AddModule"
/>
</ListItem>
)
}
})
return (
<div className="ModulesList">
<List>
{ListItemsUI}
</List>
</div>
)
One more thing map is not suitable for these cases where you want to return only few element on the basis of condition, use forEach for that. Reason is if you don't return anything, by default map will return undefined.
Check the output of this example:
let a = [1,2,3,4,5,6,7,8];
let b = a.map(el=>{
if(el % 2 == 0)
return el;
})
console.log(b);

Categories

Resources