Mapping through objects and render in React Native - javascript

I have a React Native project where i am getting object like the attached image. I need to map through them and render description and rate from them.
How can i acheive this. I have been trying with Object.keys but not been able to do it. Here's what i have tried. Don't know if it makes sense:
{Object.keys(myObject).map(function(key, index) {
return (
<Text>
{myObject.map((rate, description) => {
return (
rate,
description
)
})
</Text>
}

If you're just trying to map the rate and description, you don't need the second map -- you can just use the key to get the entry from the original object and then access its properties directly:
{Object.keys(myObject).map(key => {
const item = myObject[key];
return (<View>
<Text>{item.rate}</Text>
<Text>{item.description}</Text>
</View>
)})}

You can not use map on objects so try with bellow code
<>
{Object.keys(myObject).map((key, index)=>
<Text>{myObject[key].description}, {myObject[key].rate}</Text>
)
}
</>

Related

How to solve Text strings must be rendered within a <Text> in nested map?

I'm not finding a way to solve this error in my nested map function , everything that I try ends up in a sintax error.
My code:
{import codes....}
const FormScreen = ({route}) => {
const [FieldForm, setFieldForm] = useState([]);
const [TypeForm, setTypeForm] = useState([]);
useEffect(() => {
if (FieldForm.length > 0) {
return;
} else {
setFieldForm(JSON.parse(route.params.paramKey).message);
setTypeForm(JSON.parse(route.params.paramKey).tipo);
console.log('SETINGGG',FieldForm,TypeForm);
}
},[FieldForm,TypeForm]);
return (<View>
{FieldForm.length > 0 ? (
FieldForm.map((item) => (
<>
<Text>{`${JSON.stringify(item)}`}</Text>
<>
{TypeForm.map((type) => (
<Text>{`${JSON.stringify(type)}`}</Text>
))}
</>
</>
))
) : (
<Text key={uuid.v4()}> Loading ...</Text>
)}
</View>
I tried to remove these components but it not worked, how can I make it work ?
{TypeForm.map((type) => (
<Text>{`${JSON.stringify(type)}`}</Text>
))}; // remove this ; (dot and comma)
You could utilize a template string like {`${type}`}
I would think you're going to end up with [Object] as your text body, but that's a good starting point to start getting the values that you want.
Edit: The ` are called backticks and they're used for creating template strings or string literals. Instead of using double quotes to represent a string value, we use these. Template strings are able to have nested object values inside of them and print their string representation. If it's just a JSON object that you're trying to print in the template string, you're going to wind up printing [Object]. That's going to tell you that you're not actually printing the value of the object that you want, and you're probably after type.value, but to find the key/value of the object that you may be looking for, you could try something like <Text>{`${JSON.stringify(type)}`}</Text>.

React render quantity of components based on a numeric value

I want to pass in a value to a component and render multiple child components based on that value. e.g. if I pass in count={4} in props, then I want to render 4 <Icon/> components. If I pass in 5, I want to render 5, and so on.
At the moment, all I can think to do is to take the value and turn it into an array (i.e. do a for loop and push a placeholder element to an array with each iteration) and then do a map on that array. But that seems like overkill.
Is there a simple solution to this?
You can do it like this:
...
return(
Array.from({length: props.count}, () => <Icon />)
)
You're probably looking a way to map amount of children to be populated. Check this live example: https://snack.expo.io/#zvona/mapping-child-components
This is the core code from that example:
const Icon = ({index}) => (
<View><Text>{`Icon #${index + 1}`}</Text></View>
);
const Icons = ({count}) => (
Array.from({length: count}).map((_item, index) => <Icon index={index}/>)
)
const App = () => {
return (
<View style={styles.container}>
<Icons count={5} />
</View>
);
}
You can use a simple for loop for this
for(let i = 0; i < count ; i++){
return <Icon />
}
If this doesn't work, you can do the following. It's a bit modern es6 function. Try this..
{[...Array(count)].map((x, i) =>
<Icon key={i} />
)}

React.js: How to filter JSX element array on custom attribute?

I am starting with a simple array of JSX elements:
const jsxArray = dataItems.map(item => (
<div>
<Header>{item.title}</Header>
<Paragraph>{item.body}</Paragraph>
<Paragraph customAttribute={item.isActive} >{item.tags}</Paragraph>
</div>
))
Inside render, or rather return since I use functional components for everything now, I'd like to filter for JSX elements where the isActive attribute was tagged true.
return (
{jsxArray
.filter(jsxElement => // want to filter in JSX elements
// that are true for customAttribute keyed to `item.isActive`)
}
)
Is there any way to do it?
If there is not precisely a good way I am open to workarounds.
It is possible for me to simply filter the array at an earlier step. It would result in some extra code duplication though, since I would still need the array of unfiltered JSX elements elsewhere.
You don't filter the list after you render it. At that point it's just a tree of nodes that doesn't have much meaning anymore.
Instead you filter the items first, and then render only the items that pass your criteria.
const jsxArray = dataItems.filter(item => item.isActive).map(item => (
<div>
<h3>{item.title}</p>
<p>{item.body}</p>
<p customAttribute={item.isActive} >{item.tags}</p>
</div>
))
It is possible for me to simply filter the array at an earlier step. It would result in some extra code duplication though, since I would still need the array of unfiltered JSX elements elsewhere.
Not necessarily. When dealing with filtering like this myself I create two variables, one for the raw unfiltered list and one for the filtered items. Then whatever you're rendering can choose one or the other depending on its needs.
const [items, setItems] = useState([])
const filteredItems = items.filter(item => item.isActive)
return <>
<p>Total Items: ${items.length}</p>
<ItemList items={filteredItems} />
</>
Instead of accessing the jsx element properties (which I think it's either not possible or very difficult) I suggest you to act in this way:
Save the renderer function for items in an arrow function
const itemRenderer = item => (
<div>
<Header>{item.title}</Header>
<Paragraph>{item.body}</Paragraph>
<Paragraph customAttribute={item.isActive} >{item.tags}</Paragraph>
</div>
)
Save the filter function in an arrow function
const activeItems = item => item.isActive
Use them to filter and map
const jsxArray = dataItems.filter(activeItems).map(itemRenderer)
Use them to map only
const jsxArray = dataItems.filter(activeItems).map(itemRenderer)
Hope this helps!
Usually you would filter the plain data first and then render only the markup for the filtered elements as described in #Alex Wayne answer.
If you worry about duplication of the markup, that can be solved by extracting a component from it:
const Item = ({title, body, isActive, tags}) => (
<div>
<Header>{title}</Header>
<Paragraph>{body}</Paragraph>
<Paragraph customAttribute={isActive}>{tags}</Paragraph>
</div>
);
For rendering the filtered list you can then do:
{items.filter(item => item.isActive).map(item => <Item {...item} />)}
and for the unfiltered list:
{items.map(item => <Item {...item} />)}

reactjs ,jsx iterate over nested object

i have an reactjs application which contains all child object, i want to iterate over them few things i have tried like
cart.line_items.map(items =><CartPreview key={items.id} data = {items} />)}
and cart preview is like bellow
import React from 'react'
export default (props) => {
const { data } = props
return (
<a href={Routes.spree_cart_path()}>
<span className="glyphicon glyphicon-shopping-cart" />
{I18n.t('spree.cart')}: {I18n.toCurrency(data.total)}
</a>
)
}
its print total of line_items object which is fine..
Now i want to go further (i want to get variant and image object in line items) in line item object and i did like
{ !cart.isFetching && cart.line_items.map
(
function(variant, key)
{
return(
Object.keys(variant).map
(
function(images)
{
return
(
<CartPreview variant={variant} image={images} />
);
}
)
)
}
)
}
which gives undefined variant and line_items
Can anyone please help me ...
for understanding i have attached screen shot too...
Hope I understand your question correctly. Your code doesn't make much sense to me. No sure if the approach below is what you want.
I assume that for each image, you want to render one CartPreview.
{
!cart.isFetching && cart.line_items.map(
line_item =>
line_item.variant.images.map(image => <CartPreview variant={line_item.variant} image={image} />))
}
I feel that you are a bit confused about Object.keys and map. You can go check the documents, it will give you a clear idea of iterating an array in javascript.

Using map to iterate through two arrays

Currently in React, I am using array.map(function(text,index){}) to iterate through an array. But, how am I going to iterate through two arrays simultaneously using map?
EDIT
var sentenceList = sentences.map(function(text,index){
return <ListGroupItem key={index}>{text}</ListGroupItem>;
})
return (
<div>
<ListGroup>
{sentenceList}
</ListGrouup>
</div>
);
Like, in this I want icons to be prepended with every iteration. And I'm planning to have those icons in another array. So, thats why iterate two arrays.
If at all possible, I would recommend storing the text alongside the images in an array of objects, eg:
const objects = [{text: 'abc', image: '/img.png' }, /* others */];
that way you can just iterate through the array and select both members at the same time, for example:
objects.map(item => (<Component icon={item.image} text={item.text} />) )
If this isn't possible then just map over one array and access the second array's members via the current index:
sentences.map((text, index) => {
const image = images[index];
return (<Component icon={image} text={text} />);
});
Are the both arrays of same length? You can do something like below if your intention is to combine both in some way.
array.map(function(text,index){
return text + ' ' + array2[index]
})
In your case:
var sentenceList = sentences.map(function(text,index){
return <ListGroupItem key={index}>{text} <img src={icons[index]} /i> </ListGroupItem>;
})
return (
<div>
<ListGroup>
{sentenceList}
</ListGrouup>
</div>
);
Notice, How Icon src is being assigned. The idea is that access icons array with the same index to get a corresponding icon.
You can't do this with built-in Array.prototype methods, but you can use something like this:
function map2(arr1, arr2, func) {
return arr1.map(
(el, i) => { return func(el, arr2[i]); }
);
}
(Of course, arr1 and arr2 are expected to have the same length)
Generally, what you're looking for is a zip function, such as the one that lodash provides. Much like a real zipper, it combines two things of the same length into one:
const zipped = _.zip(sentences, icons);
return (
<div>
<ListGroup>
{zipped.map(([sentence, icon], index) => (
<ListGroupItem key={index}><Icon icon={icon} /> {text}</ListGroupItem>;
))}
</ListGroup>
</div>
);
Note, this is doing more iterations than are technically needed. If performance is an issue, you may want a solution that's a bit smart (not really in scope for your question though).

Categories

Resources