props.array.map is not a function - javascript

I have a few components that are to render dynamically based on values passed through props. My main component(1) is dynamically creating its subcomponents(2) and passing values into those components via props. Each component(2) created is then supposed to utilize the values in props to create new subcomponents(3) of this component.
The problem arises when I try to map the object array passed as props in component 2. Component 1 successfully creates components 2, but component 2 displays the error "this.props.section.map is not a function". I'm using the exact code from component one, the only difference is I am referencing the array via props.
this.state = {
menuSections: [
{
id: 1, title: 'Starters', menuItem: [{
id: 1,
name: 'Meatball',
description: 'Large Meatball',
price: '11 meatballs'
}]
},
{
id: 2, title: 'Starters', menuItem: [{
id: 2,
name: 'Meatball',
description: 'Large Meatball',
price: '11 meatballs'
}]
},
{
id: 3, title: 'Starters', menuItem: [{
id: 3,
name: 'Meatball',
description: 'Large Meatball',
price: '11 meatballs'
}]
},
],
{this.state.menuSections.map(menuSection => (<MenuSection
section={menuSection} mobileMode={this.state.mobileMode} />))}
This is the code from my App component, which works like a charm. the code for my 2nd component (MenuSection) is where the problem arises.
{this.props.section.map((itemContainer, i) => (<ItemContainer styles={styles}
image={imageFood1} title={itemContainer.menuItem[i].name}
description={itemContainer.menuItem[i].description}
price={itemContainer.menuItem[i].price} />))}
Ideally, the section.map function in the 2nd component will render each individual menu item based on the props passed from the Main app. Instead, I receive the error "this.props.section.map is not a function".
edit: I know variations of this question have been asked before, but I have tried numerous suggestions, none of which have worked.

this.props.section is going to be an Object like :
{
id: 1, title: 'Starters', menuItem: [{
id: 1,
name: 'Meatball',
description: 'Large Meatball',
price: '11 meatballs'
}]
}
So you can't .map it ,
either you pass the array :
{
this.state.menuSections.map(menuSection => (
<MenuSection
section={menuSection.menuItem}
id={menuSection.id}
title={menuSection}
mobileMode={this.state.mobileMode}
/>
))
}
Or, you map the array inside :
{
this.props.section.menuItem.map((itemContainer, i) => (
<ItemContainer
styles={styles}
image={imageFood1} title={itemContainer.menuItem[i].name}
description={itemContainer.menuItem[i].description}
price={itemContainer.menuItem[i].price}
/>
))
}

Section is an Object.
this.props.section.menuItem.map()

Related

Separate big array from main component to a new file

I'm new in the front end world, and I currently working on Angular project with typescript, and I created an array in order to assign to an object, so I have something like this in my TS component:
formOptions = []
ngOnInit() {
this.formOptions = [{
id: 1,
description: 'First name'
},
{
id: 2,
description: 'Middle name'
}, {
id: 3,
description: 'Last name'
}...etc
}
As you can see the array it's going to be supper big, is there a way to move the array to separate file, then import it and just assign the object? If so, where is the common path to save this path of files and what extension I should use for it?
Try storing the array in a separate .json file. Then use fetch to load the file and parse the JSON. JSON is Javascript Object Notation and it will take an array (or object) exactly as you have it laid out in your code.
[{
id: 1,
description: 'First name'
},
{
id: 2,
description: 'Middle name'
}, {
id: 3,
description: 'Last name'
}...etc
}]
The first example at MDN does exactly what I describe.

How to update a recurring nested object property using its previous value using Javascript?

I got an array with some elements and each element has some properties like name, id and children. Each element has children property and then sub children so on and so forth. This array is already there in our application. Now I want to update all of elements and sub elements of our array with a new property called "path". The "path" will be the key and its value will be the addition of its previous object's name. For example
let dataArray = [
{
name: 'Data',
id: 12,
path: 'Data',
children: [
{
name: 'Data Center',
id: 13,
path: 'Data/Data Center',
children: [
{
name: 'Data Management',
id: 13,
path: 'Data/Data Center/Data Managemet',
},
],
},
],
},
{
name: 'Machine',
id: 12,
path: 'Machine',
children: [
{
name: 'Machine Center',
id: 13,
path: 'Machine/Machine Center',
children: [
{
name: 'Machine Management',
id: 13,
path: 'Machine/Machine Center/Machine Managemet',
},
],
},
],
}
];
As you can see path property to all the elements. I want to make this happen programatically. For that, here is the piece of code I have written but I am not able to understand what need to need to be done to achieve. This piece of code adds path property to all the elements and sub elements but with name as path like above example. I want the addition of previous names which have been traversed.
addPathProperty(){
dataArray.forEach((element) =>{
element.path = element.name;
if(element.children.length > 0){
this.addPathProperty(element.children)
}
});
}
Here is the link Stackblitz. Any help will be appreciated. Thank you
I think this code should work:
const appendPath = (root = '') => (obj) => {
obj.path = root ? `${root}/${obj.name}` : obj.name
if (obj.children) {
obj.children.forEach(appendPath(obj.path))
}
}
dataArray.forEach(appendPath())
appendPath is a function that accepts a root, when this function is invoked, it will combine root and name and set this to object.path; After that, it will do the same for the object.children if they exists

Update Redux store with reducer recursively

I’ve been working on a bit of a lazy load recursive tree view, and while I have the component level stuff working, I’m having a bit of difficulty trying to work out how to make it play nicely with redux.
For simplicity, let’s say I have the following data structure in redux
[
{
id: 'myId1',
value: 'Tree View top level 1',
fetchedChildren: []
},
{
id: 'myId2',
value: 'Tree View top level 2',
fetchedChildren: []
},
…and so on
]
I have my recursive component working so that when you click on an item, the relevant id is sent to the API and a collection of children is returned. Clicking myId2 would result in the data looking like this
[
{
id: 'myId1',
value: 'Tree View top level 1',
fetchedChildren: []
},
{
id: 'myId2',
value: 'Tree View top level 2',
fetchedChildren: [
{
id: 'myId3',
value: 'Tree View second level 1',
fetchedChildren: []
},
{
id: 'myId3',
value: 'Tree View second level 2',
fetchedChildren: []
},
]
},
]
and then the idea is that this could theoretically go on for infinity.
below is an example of my reducer that updates the store correctly from the above first example to the second (the tree is linked to data)
case FETCH_CHILDREN_SUCCESS:
return {
...state,
loading: false,
error: null,
data: state.data.map(leaf=> leaf.id === action.payload.id ? {
...leaf,
value: leaf.value,
fetchedChildren: action.payload.fetchedChildren.map( child => {
return {
...child,
value: child.value
}
})
} : leaf)
};
This will work to populate fetchedChildren on the second level, but how do you do this recursively for subsequent levels?
I took a look at the tree-view sample in the redux source code, and the way they are managing the data is to have a flat array that is linked by ids to identify parents.
Is the above the wrong way to look at it, and should I be looking at doing this in a flat array like the redux example?

Object.keys() return not working in Ant Design table column rendering

I'm trying to render an Ant Design table featuring a people column which should look like this:
Adults: 2 Children: 3
Here's a sample dataSource object:
{
id: 'KRO066',
key: 'KRO066',
date: '01/01/2020',
people: { adults: 2, children: 3 },
status: 'Confirmed',
total: '563.25',
}
Here's the people column render function in my column object:
{
title: 'People',
dataIndex: 'people',
key: 'people',
render: people => Object.keys(people).forEach(function (type, i) {
return <span key={i}><strong>{type}:</strong>{people[type]}</span>;
})
}
The column does not return anything, instead, I get an empty cell.
What's wrong with the render function?
Use Object.keys(people).map instead of Object.keys(people).forEach
Credit #Hamms in the question comments

problem with infinite loop in function hook useEffect

I have a problem with an infinite loop on my hook,
I'm passing the data of the local JSON breakfast. If you are iterating with map the data and I am taking it to paint a menu of buttons.
If I remove the data at the end of the function, and leave the empty array, it sends me the following error:
const BreakfastComponent = () => {
const breakfast = [
{
id: 0,
name: "Sandwich de jamón y queso",
price: '35',
img: "https://i.ibb.co/ynC9xHZ/sandjc.png",
},
{
id: 1,
name: "Jugo Natural",
price: '15',
img: "https://i.ibb.co/8mrd4MK/orangejuice.png",
},
{
id: 2,
name: "Café americano",
price: '20',
img: "https://i.ibb.co/nsj1GL0/americancoffe.png",
},
{
id: 3,
name: "Café con leche",
price: '28',
img: "https://i.ibb.co/GRPBm7j/coffeandmilk.png",
}
];
const [stateProduct, setStateProduct] = useState([ ]);
useEffect(() => {
setStateProduct(breakfast);
}, [breakfast]);
return (
<section className="databreakfast">
{stateProduct.map((element, item) =>
<ButtonsBComponent
key={item}
{...element}
/>
)}
</section>
)
};
export default BreakfastComponent;
React Hook useEffect has a missing dependency: 'breakfast'. Either include it or remove the dependency array react-hooks/exhaustive-deps
The problem is simple, you have breakfast array as a dependency to useEffect and in useEffect you are setting the breakfast array itself. Now since the const breakfast array is declared inside the component, a new reference to it is generated everytime and since useEffect sets the array in state, it re-renders and on next re-render the comparison for breakfast array fails since the reference has changed.
The solution is simple, you don't need to have the const array in the component and also you don't need to use useEffect
const breakfast = [
{
id: 0,
name: "Sandwich de jamón y queso",
price: '35',
img: "https://i.ibb.co/ynC9xHZ/sandjc.png",
},
{
id: 1,
name: "Jugo Natural",
price: '15',
img: "https://i.ibb.co/8mrd4MK/orangejuice.png",
},
{
id: 2,
name: "Café americano",
price: '20',
img: "https://i.ibb.co/nsj1GL0/americancoffe.png",
},
{
id: 3,
name: "Café con leche",
price: '28',
img: "https://i.ibb.co/GRPBm7j/coffeandmilk.png",
}
];
const BreakfastComponent = () => {
const [stateProduct, setStateProduct] = useState(breakfast);
return (
<section className="databreakfast">
{stateProduct.map((element, item) =>
<ButtonsBComponent
key={item}
{...element}
/>
)}
</section>
)
};
export default BreakfastComponent;
useEffect's second argument is an array of state/hooks to be watched and when they change, to run the effect. Since your breakfast is a const, I'm guessing you just want the original stateProduct to be breakfast. So instead of using [] as the default, use breakfast.
const [stateProduct, setStateProduct] = useState(breakfast);
Also, probably a good idea to declare const breakfast ... outside of your react functional component so it doesn't re-declare it on every re-render.

Categories

Resources