get undefined for array element react - javascript

I'm getting undefined when accessing element of array but console showed value when using the array name only.
The code:
const Part = (props) => {
return <p>{props.name} {props.exercises}</p>
}
const Content = (props) => {
// when i use console.log(props[0])
// it shows undefined
//
// but when i use console.log(props)
// it shows the array information as
// {parts: Array(3)}
// parts: Array(3)
// 0: {name: 'Fundamentals of React', exercises: 10}
// 1: {name: 'Using props to pass data', exercises: 7}
// 2: {name: 'State of a component', exercises: 14}
// length: 3
// [[Prototype]]: Array(0)
// [[Prototype]]: Object
return (
<div>
<Part parts={props[0]} />
</div>
)
}
const App = () => {
const course = 'Half Stack application development'
const parts = [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
return (
<div>
<Content parts={parts} />
</div>
)
}
So I don't understand why in Content, console.log(props) returns array info but console.log(props[0])says undefined, which gets nothing in App.
Update:
Thanks for everyone's reply. Now I know if I use 'props.parts' inside Content, I will get the right result. Then I got another question (Sorry I'm new to JS and React) :
Because 'parts' is defined in App and passed to Content. I shouldn't use or know 'parts' when defining Content. So why do I need to use 'props.parts' inside Content?

// when i use console.log(props[0])
// it shows undefined
because the array variable name is parts as you have mentioned here:
// but when i use console.log(props)
// it shows the array information as
// {parts: Array(3)}
// parts: Array(3)
So try this:
console.log(props.parts)
or
console.log(props.parts[0])

console.log(props) not return array, it return object has 1 attribute name parts(parts is array)
=> Solution:
const Content = props => {
const { parts } = props;
return (
<div>
<Part parts=parts[0] />
</div>
)
}

Related

I'm trying to add to an array of objects that is broken into two inputs in React

So I have an array of objects where the keys are 'cost' and 'service' called estimate. You can add to the array by clicking 'Add' which adds a new index (i) to the array. The issue is on the first cycle I get a good array of {'cost': 2500, 'service': "commercial cleaning"} (imgSet-1) but when I add another item it completely erases the array and sets only one of the nested objects key and value. (imgSet-2). This is the outcome I'm looking for once the state has been saved (imgSet-3) I have tried going with #RubenSmn approach but then I receive this error. (imgSet-4)
imgSet-1 *********
Adding an initial service
Outcome of the initial service addition
imgSet-2 *********
Adding the second service
Outcome of the second service addition
imgSet-3 *********
imgSet-4 *********
Below is the code for the part of the page where you can add services and the output of the text inputs.
const [estimate, setEstimate] = useState([]);
{[...Array(numServices)].map((e, i) => {
return (
<div key={i} className="flex justify-between">
<div>
<NumericTextBoxComponent
format="c2"
name={`cost-${i}`}
value={estimate?.items?.["cost"]?.[i]}
change={(e) =>
setEstimate({ ...estimate, items: [{...estimate?.items?.[i],cost: e?.value}]})
}
placeholder='Price'
floatLabelType="Auto"
data-msg-containerid="errorForCost"
/>
</div>
<div>
<DropDownListComponent
showClearButton
fields={{ value: "id", text: "service" }}
name={`service-${i}`}
value={estimate?.items?.["service"]?.[i]}
change={(e) =>
setEstimate({ ...estimate, items: [{...estimate?.items?.[i],service: e?.value}]})
}
id={`service-${i}`}
floatLabelType="Auto"
data-name={`service-${i}`}
dataSource={estimateData?.services}
placeholder="Service"
data-msg-containerid="errorForLead"
></DropDownListComponent>
<div id="errorForLead" />
</div>
</div>
);
})}
</form>
<button onClick={() => setNumServices(numServices + 1)}>Add</button>
I have tried multiple variations of spread operators but I can't seem to get it to work. My expected result would be:
estimate:{
items: [
{'cost': 2500, 'service': 'Commercial Clean'},
{'cost': 500, 'service': 'Bathroom Clean'},
{'cost': 180, 'service': 'Apartment Clean'},
{etc.}
]
}
The initial state is an array which is not the object you're setting in the change handlers. You can have an initial state like this.
const [estimate, setEstimate] = useState({ items: [] });
You're not adding back the old items of the state when you're setting the new state.
setEstimate({
...estimate,
items: [{ ...estimate?.items?.[i], cost: e?.value }],
// should be something like
// items: [...estimate.items, { ...estimate.items?.[i], cost: e?.value }],
});
But you can't do that since it will create a new object in your items array every time you change a value.
I made this dynamic handleChange function which you can use for you state changes. The first if statement is to check if the itemIndex is already in the items array. If not, create a new item with the propertyName and the value
const handleChange = (e, itemIndex, propertyName) => {
const newValue = e?.value;
setEstimate((prevEstimate) => {
if (prevEstimate.items.length <= itemIndex) {
const newItem = { [propertyName]: newValue };
return {
...prevEstimate,
items: [...prevEstimate.items, newItem]
};
}
// loop over old items
const newItems = [...prevEstimate.items].map((item, idx) => {
// if index' are not the same just return the old item
if (idx !== itemIndex) return item;
// else return the item with the new service
return { ...item, [propertyName]: newValue };
});
return {
...prevEstimate,
items: newItems,
};
});
};
For the Service dropdown, you can do the same for the Cost just change the property name
<DropDownListComponent
...
value={estimate.items[i]?.service}
change={(e) => handleChange(e, i, "service")}
...
></DropDownListComponent>
See here a simplified live version

React use True/False for .filter.map

I have a site, where i want so filter my pictures via tags.
the filter is made with checkboxes, which are generated by the tags themselves.
i break down the code to the nessessary:
const [filteredTags, setFilteredTags] = useState();
// {wedding: false, couple: true, NSWF: true} <-this is the ouput of console.log(filteredTags)
const PortfolioData= [
{
name: "John & Johna ",
tag: ["wedding", "couple"],
img: [ src1 , src2, ...] //irrelevant
},
{
name: "Mario & Marie",
tag: ["couple", "NSFW"],
img: [ src1 , src2, ...] //irrelevant
},
];
return(
<>
{PortfolioData
.filter(visible => visible.tag.includes( ??????? )) //<- what to write ?
.map((PortfolioData) => {
return (
<Tile
header={PortfolioData.name}
imgSrc={PortfolioData.mainImg[0]}
/>
);
})}
</>
)
How can I filter this?
Check that .some of the tags being iterated over are truthy in the filteredTags object. (To make things easier to manage, it'd be good to set filteredTags to also have an initial value of an empty object, and not undefined)
const [filteredTags, setFilteredTags] = useState({});
// for TypeScript:
// const [filteredTags, setFilteredTags] = useState<Record<string, boolean | undefined>>({});
{PortfolioData
.filter(collection => collection.tag.some(tag => filteredTags[tag]))

react Map is not returning any jsx

I am looping over the people array and getting the first array. My screen should say "person 1". but it is blank and
nothing is being returned.
const people = [
[
{
name: 'person 1'
}
],
[
{
name: 'person 2'
}
],
]
export default function Index() {
return (
<>
{people.slice(0,1).map((person) => {
return <h1>{person.name}</h1>
})}
</>
)
}
the code works when i do this, but I need to use slice
export default function Index() {
return (
<>
{people[0].map((person) => {
return <h1>{person.name}</h1>
})}
</>
)
}
people.slice(0, 1), unlike you'd expect, returns [[{ name: "person 1" }]], not [{ name: "person 1" }] (Array#slice returns a "slice" of an array, and in your special case it's an array with a single value, but not the single value itself). You'll have to access the inner array to get what you want:
// in your JSX
people.slice(0, 1).map(([person]) => (
<h1>{person.name}</h1>
))
Notice that the argument destructures the input array (this assumes each value in people is an array with exactly one element; if not, loop over that content).
Another option would be to Array#flatMap to "un-nest" those values:
// in your JSX
people.slice(0, 1).flatMap(person => (
<h1>{person.name}</h1>
))
This will work:
return (
<>
{people.slice(0,1).map((person) => {
return <h1>{person[0].name}</h1>
})}
</>
)
Because each person is still an array, you can't access the object's properties directly without first accessing the array that wraps it.
You have to modify the data structor of people.
const people = [
{
name: 'person 1'
},
{
name: 'person 2'
}
];
In you case, person in map method is Array type. So, person.name's value will be undefined.

Content not loading and logging with delay

I'm doing a React project for my bootcamp and I'm passing a details array as a descripcion props from my ItemDetailContainer component to my ItemDetail component. When I try to console.log my descripcion props in ItemDetail, it first logs an empty array and after a few seconds it logs the actual array with my product's details.
The problem is that the ItemDetails component is not rendering the data from the array but I can log its content.
I thought this was caused do to the setTimeOut function or UseEffect hook in my code but I still get this problem when I remove them
My ItemDetailContainer code:
import { useState, useEffect } from "react";
import Product from "../../product.json";
import ItemDetail from "./ItemDetail";
import { Link } from "react-router-dom";
const ItemDetailContainer = () => {
const [details, setDetails] = useState([]);
const getItem = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Product)
}, 2000);
});
}
useEffect(() => {
getItem().then(setDetails)
}, []);
return (
<>
<div className="producto-descripcion">
<ItemDetail descripcion={details}></ItemDetail>
</div>
<button class="back-shopping"><Link className="route-link" to="/category/:id">go back to shopping</Link></button>
</>
)
}
export default `ItemDetailContainer`
My ItemDetail code:
import { useParams } from "react-router"
const ItemDetail = ({descripcion}) => {
console.log(descripcion)
const { id } = useParams();
return (
<>
<div className="produc-desc" id={id}>
{descripcion.filter(desc => desc.id === id).map((desc, index) => (
<div key={index}className="full-card">
<h2>{desc.name}</h2>
<img src={desc.pictureURL} alt="unisex hoodie" id="picture-store"/>
<p>{desc.price}</p>
<h4 id="texto-descripcion">{desc.description}</h4>
</div>
))}
</div>
</>
)
}
export default ItemDetail
The output of the console.log in the ItemDetail component:
Array(0)
and then:
(4) [{…}, {…}, {…}, {…}]
0: {id: 1, name: 'PHONE CASE', stock: '17', price: '$9.99', pictureURL: 'https://www.montblanc.com/variants/images/19971654706771425/A/w2500.jpg', …}
1: {id: 2, name: 'PINK HOODIE', stock: '12', price: '$24.99', pictureURL: 'https://cdn.shopify.com/s/files/1/0040/6146/2626/p…87992ClLogoHoodiepinkfront_1200x.png?v=1628299298', …}
2: {id: 3, name: 'WHITE SHIRT', stock: '23', price: '$14.99', pictureURL: 'https://hips.hearstapps.com/vader-prod.s3.amazonaw…m/1623333444-61jgr5y0ibl-ac-ul1500-1623333437.jpg', …}
3: {id: 4, name: 'BLACK HOODIE', stock: '9', price: '$24.99', pictureURL: 'https://ninefoldpath.org/wp-content/uploads/2018/05/NINE-BEATS-Logo-hoodie-600x600.jpg', …}
length: 4
What am I missing? Let me know if I wasnt clear. Thanks in advance.
The first time react renders the details state is [] therefore the first time it renders you see Array(0) in the console, and right after you see the desired array values, that is normal and expected React behaviour.
What you can do is something like this:
const ItemDetail = ({descripcion}) => {
console.log(descripcion)
const { id } = useParams();
return (
{
(description.length > 0) ?
<div className="produc-desc" id={id}>
{descripcion.filter(desc => desc.id === id).map((desc, index) => (
<div key={index}className="full-card">
<h2>{desc.name}</h2>
<img src={desc.pictureURL} alt="unisex hoodie" id="picture-store"/>
<p>{desc.price}</p>
<h4 id="texto-descripcion">{desc.description}</h4>
</div>
))}
</div>
: <div>Getting data</div>
}
)
}
export default ItemDetail
So you render a different message, in this case "Getting data" and as soon as the state changes you render the desired JSX, hope that makes sense.
There are many different ways to tackle this, I'm just giving you a simple workaround, you may want to check useEffect that will help you take more control over your component render lifecycles.
Finally solved it, basically the filter was comparing the useParams id which is a string to an integer id. Solved with a toString() like this:
Before desc.id === id after desc.id.toString() === id

How can I change defaultValue of input when I have got props from the server in admin-on-rest?

I'm working with admin-on-rest and I'm creating <Edit> component. In <Edit> I have <RadioButtonInputGroup> with defined defaultValue:
const defaultValues = {
user_to_app_to_role_by_user_id: 5
};
...
const roleChoices = [
{ id: 5, name: 'User' },
{ id: 4, name: 'Admin' }
];
...
<Edit title="Edit user">
<SimpleForm defaultValue={defaultValues}>
<RadioButtonGroupInput
label="Role"
source="user_to_app_to_role_by_user_id"
choices={roleChoices}
/>
...
But now I want to et up default value like value that I want to get from this.props, like this:
const defaultValues = {
user_to_app_to_role_by_user_id: this.getRoleByProps()
};
...
getRoleByProps() {
let role;
if(this.props.user && this.props.user.roles) {
return this.props.user.roles[0].role_id
}
else {
return 5;
}
}
In process of debugging I see, that when properties come in, my defaultValues object update. But what's problem is that component <RadioButtonGroupInput> doesn't update. It's value as before.
I already tried to inpur default velues in state and write <SimpleForm defaultValue={this.state.defaultValues} but it doesn't help.
Maybe you can give some advice for me what I can do in thi situation.

Categories

Resources