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.
Related
I'm sorry that this question has been asked in a similar fashion. I've read through a lot of similar threads but just don't know enough to apply it to my little project. I'm very new to React so I would appreciate any help!
Getting to it, I'm making a pokemon game where someone can hit click buttons to filter down a JSON list of pokemon. They can go by type,weaknessess,etc.
But I'm a little confused in keeping a 'global array' if that's the right word. It may be something I don't understand with React's useState.
Here's my code
import React, { useState, useEffect } from "react";
import "./App.css";
import PokemonLibrary from "./data/PokemonList.json";
export default function App() {
const [pokemonData, setPokemonData] = React.useState(PokemonLibrary.pokemon);
const pokeListCopy = PokemonLibrary.pokemon;
const filterTypeOne = () => { //filter type
const myFilteredPoke = pokeListCopy.filter((pokeType) => {
return pokeType.type.includes("Grass");
});
console.log(myFilteredPoke); // shows array of objects of left over pokemon
setPokemonData(myFilteredPoke);
};
const filterWeakness = () => { //filter weakness
const myFilteredPoke = pokeListCopy.filter((pokeType) => {
return pokeType.weaknesses.includes("Ice");
});
setPokemonData(myFilteredPoke);
};
return (
<div className="App">
<h1>Pokemon Selector!</h1>
<div>
<button onClick={filterTypeOne}>Filter Grass</button>
<button onClick={filterWeakness}>Weak to Ice</button>
</div>
{pokemonData &&
pokemonData.map((poke) => (
<p key={poke.id}>
#{poke.num} | {poke.name} | {poke.type[0]} {poke.type[1]}
<img src={poke.img} alt="Pokemon Images"></img>
</p>
))}
</div>
);
}
My question is, how do I keep a consistent array for these two functions (and more) to pull the same data from? I'd like it to be able to be filtered in either order. But currently, these filter separate arrays. I've played with it a lot using normal JavaScript, but I can't quite figure this out.
I hope that was enough information. Please let me know if this didn't make sense! I'd appreciate any guidance. Thank you.
Problem
You are facing this problem because you try to set the state of the list in an "imperative" manner, but React is meant to be used more "declarative". That means, what you try here is like:
"if I click the button, change the list to contain the items that contain 'Grass'",
but how you should use React is:
"if I click the button, then the state of my component should be that the list only contains items with 'grass'"
That might sound like the same, but there is a subtle difference. React is good in changing a state dependent on some other state. You might say "but that's what I'm trying to do, changing the state of the list", but then you have tell the full story
"if I click the button, and the list is not filtered already, and maybe contains the items X, then change the list to contain the items that contain 'Grass', unless ..."
This becomes quite complicated, especially comparing contents of lists and components.
Solution
There are different solutions to your problem, but what you should do is basically something like:
set the component state to describe what you want
have other parts of your program (and React) take care to give you a the list dependent on this description
e.g.:
const [pokemonData, setPokemonData] = React.useState(PokemonLibrary.pokemon);
const [listState, setListState] = React.useState({ type: '', weekness: '' });
useEffect(() => {
let newList = pokemonData;
if( listState.type === 'Grass' ){
newList = newList.filter( ... );
}
if( listState.weekness === 'Ice' ){
newList = newList.filter( ... );
}
setPokemonData(newList);
}, listState );
return (
<div>
<button onClick={()=>{ setListState({ ...listState, type: 'Grass' }) }}>Filter Grass</button>
{ pokemonData.map( (poke) => ... ) }
</div>
);
(This code is not very elegant and would not even work, and should only illustrate the idea. From here on there are several ways how to implement the filtering mechanism)
The reason why I want to use react-window is to avoid excessive DOM problem. Also, because I'm using nextjs and React.lazy() doesn't work there. I have a Layout component in which the children are being dynamically generated, you can see the problem being solved here. However, it seems to me that it's not possible to get the height of the children beforehand.
In addition to the LayoutWrapper as shown in the previous question, the VariableSizeList is being setup for me as follow:
const [heights, setHeights] = React.useState<number[]>([])
React.useEffect(() => {
// This will actually returns [] which I don't want to happen.
// I want it to return an array of heights
const data = onMount()
setHeights(data)
}, [onMount])
const Row = ({index, style}: ListChildComponentProps) => (
<div style={style}>{childrenArr[index]}</div>
)
const getItemSize = (index: number) => heights[index]
return (
<AutoSizer disableWidth>
{({height, width}) => (
<VariableSizeList
height={height}
itemCount={childrenArr.length}
itemSize={getItemSize}
width={width}
>
{Row}
</VariableSizeList>
)}
</AutoSizer>
)
Is there any work around solution to this?
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>
)
}
</>
I am mapping through an array, and I want my variable i to be used as a unique key for my Components, however I do not know how (or where) to increment it correctly, if I add a {i++} within the <Component> tags then it will display the value of i on screen, and if I instead add {this.function(i)} and place the i++ inside the function, it will call the function but the variable i will reinitiate to the value of 0 everytime, so the key value will not be unique. I need the value of i to be the key for the component and it has to be incremented by 1 everytime, does anyone know how I can achieve this? Also, as you can see in the code, when the component is clicked it will make a function call which will send the value of i of the clicked component as a parameter to the called function.
Code:
function(i) {
console.log(i)
}
render() {
var i = 0;
var {array} = this.state;
return (
<div className="App">
{array.map(item => (
<Component key={i} onClick={(e) => this.function(i, e)}>
<p>{item.name}</p>
</Component>
))}
</div>
);
}
The map function gets a second parameter which is the index of the element:
{array.map((item, i) => (
<Component key={i} onClick={(e) => this.function(i, e)}>
<p>{item.name}</p>
</Component>
)}
Be aware that if you intend to sort this array or change its contents at runtime, then using array index as a key can cause some mistakes, as sometimes an old component will be mistake for a new one. If it's just a static array though, then using index as a key shouldn't be a problem.
.map already offer the increment, just add a second variable to the callback
render() {
var {array} = this.state;
return (
<div className="App">
{array.map((item,i) => (
<Component key={i} onClick={(e) => this.function(i, e)}>
<p>{item.name}</p>
</Component>
))}
</div>
);
}
You could try array.map((x, Key) => console.log(key)); ..
In place of console.log you could add your code, it should work fine as per your requirement.
I'm new to React and my current code works, but is there a better, "React way" (w/o ternary) of mapping through an empty array, before it has the results (without returning undefined)?
I'm rendering a materialize card for every result returned from an API search. What the code does isn't the issue because it works w/ my current solution.
Thanks in advance.
class NutritonixResultsDisplay extends Component {
render() {
const hits = this.props.nutritionixResults.hits;
return (
<div className='nutritionixResultsDiv'>
{hits
? hits.map((result, i) => (
<div key={i} className='nutritionixResultDiv'>
<Card className='cardDisplay' header={<CardTitle reveal image='' waves='light'/>}
title={result.fields.item_name}reveal={<div><p>{`Calories: ${result.fields.nf_calories}`}</p><p>{`Protein: ${result.fields.nf_protein}`}</p></div>}> <p>This is a link</p>
<p>{`Brand Name: ${result.fields.brand_name}`}</p>
</Card>
</div>
))
: ''}
</div>
);
}
}
export default NutritonixResultsDisplay;
As an alternative you can use || []:
(hits || []).map( // ... etc. )
Just simply make hits an empty array.
const hits = this.props.nutritionixResults.hits || [];