How to loop through object with 2 arrays? - javascript

Trying to loop throught State passed by props on other component
state = {
question:[firstQ, secondQ, thirdQ],
tag:[[1,2,3],[4,6],[a,b,c,d]]
}
I want to render it on next Componet with Patter like:
FirstQ
[tag1]
SecondQ
[tag2]
ThirdQ
[tag3]
etc
I was trying lot of option but getting always something like
FirstQ
SecondQ
ThirdQ
[tag1]
[tag2]
[tag3]
EDIT:
Passing data to second Component with
question={this.state.question}
tag={this.state.tag}
EDIT2:
For now i made loops like this
{this.props.question.map((item,) => {
return (<span key={item}>{item}</span>)
})}
{this.props.tag.map((item) => {
return (<span>{item<span>)
})}
I trying to render this two arrays as pairs Question1 => Tag1 then underneath second Question2 = >tag2 etc.

Use the index of question to get matching tags
Something like:
{this.state.question.map((q,i)=>{
return (
<div>
<h4>{q}</h4>
Tags: {this.state.tag[i].join()}// map these to element you want instead of join()
</div>
)
})

Related

How to loop React Elements for a specific amount of times?

I am trying to make a looper component so that I can loop any of its children for a specific amount of time.
How can I do that?
// Looper
function Looper({ children, array }) {
return (
<div>
{array.map((item) => (
<div key={item}>{children}</div>
))}
</div>
);
}
// It works, but it needs a dummy array that I don't want.
<Looper array={[1, 2, 3, 4, 5]}>
<span>Hello Guys..</span>
</Looper>
You can create an array of incrementing numbers on the fly using [...Array(times).keys()], like so:
// Looper
function Looper({ children, times }) {
const keys = [...Array(times).keys()];
return (
<div>
{keys.map((item) => (
<div key={item}>{children}</div>
))}
</div>
);
}
<Looper times={5}>
<span>Hello Guys..</span>
</Looper>
replace your map function with a for loop and pass a count i:e number of times you want the looper to render, and use that index as a key for the child divs then push them into an array. Finally, return that array of child divs. Check out this link if you want to go with this approach Loop inside React JSX

React - sort array of child components with state

Currently I'm working on a react project, but I'm seeing some unexpected behavior when sorting an array of stateful child components.
If I have a parent component
export function Parent(){
const [children, setChildren] = useState([
{name:'Orange',value:2},
{name:'Apple',value:1},
{name:'Melon',value:3}
])
var count = 0
function handleSort() {
var newChildren=[...children]
newChildren.sort((a,b)=>{return a.value-b.value})
setChildren(newChildren)
}
return (
<div>
<button onClick={handleSort}>Sort</button>
{children.map((child) => {
count++
return(<ChildComp key={count} details={child}/>)
})}
</div>
)
}
And a child component
function ChildComp(props){
const[intCount,setIntCount] = useState(0)
function handleCount(){
setIntCount(intCount+1)
}
return (
<div>
<p>{props.details.name}</p>
<button onClick={handleCount}>{intCount}</button>
</div>
)
}
When the page first renders everything looks great, three divs render with a button showing the number of times it was clicked and the prop name as it was declared in the array. I've noticed that when I sort, it sorts the props being passed to the child components which then rerender, but the intCount state of the child component stays tied to the original location and is not sorted. is there any way to keep the state coupled with the array element through the sort while still maintaining state data at the child level, or is the only way to accomplish this to raise the state up to the parent component and pass a callback or dispatch to the child to update it?
The count is not is not sorted. It just got updated when you sorted.
Keys help React identify which items have changed, are added, or are
removed. Keys should be given to the elements inside the array to give
the elements a stable identity
Every time you sort, key stay the same, as you use count.
Try using value as key
export function Parent(){
// ....
return (
<div>
<button onClick={handleSort}>Sort</button>
{children.map(child => {
return <ChildComp key={child.value} details={child}/> // key is important
})}
</div>
)
}
More info: https://reactjs.org/docs/lists-and-keys.html#keys

How can I access the data in a nested array?

I'm looping through some data. Here's the JSX: For now I'm using console.log to figure out how to access the data.
<div>
<ul>
{orderData &&
orderData.map(item => {
return <Order item={item} />;
})}
</ul>
</div>
export default function workorder({ item }) {
console.log(
Object.values(item.data).map(item => {
return item;
})
);
return <h1></h1>;
}
Right now,
console.log(
Object.values(item.data).map(item => {
return item;
})
);
returns this, which is what I want:
I can easily access the values inside all of the arrays excepting the first one, with something like item.name or item.email
But the question is: how can I access the data inside of Array(20)? I want to render data such as deadline or description.
Attempting: item.deadline returns this:
So what should I be doing here?
I belive "item" is an array, and you will want to access the array using item[0] to get an individual item. (between 0 and 19 to access individual items in the array).
It also looks like an array inside of an array, so you will have to access it twice.
So what you will want to do is use item[0][0].deadline to get the deadline property of the first object.

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} />)}

Find First Iteration of Map in React/Javascript

I'm mapping an object array in React and I want to find the first iteration of chosenFields array.
People Array:
[ { id:1, name:"Jim", occupation:"Programmer".........}
{id:2, name:"Sally", occupation:"Pet Sitter".......}]
I have another object array that is in charge of what fields are suppose to be displayed from the PeopleArray:
chosenFields Array:
[{label:"id", show:true}, {label:"name", show:true}, {label:"occupation", show:false}]
I want to know if there's a way that the code can recognize when it first iterates through chosenFields Array for each row of the People Array
renderSingleData(rowListData, currData){
//find which one is the first iteration to add a radiobox for each row
}
renderUserData(currRow){
return(
<div>
{chosenFields.map(this.renderChosenData.bind(this, currRow)}
</div>
)
}
render() {
return (
<div >
{PeopleData.map(this.renderUserData.bind(this))}
</div>
);
}
}
This is a very simplified version of the code. I need to add an iteration to a table via <td>. I'm currently using a variable in React and setting the state with a counter. I'm wondering if there's a more straightforward way to find iterations via the map function.
Take a look at the docs for Array.prototype.map()
The callback function's second argument is the index. If this is 0, then that is the first iteration of the callback. In your case, you may need to propagate that condition up a few callbacks. Something like...
renderSingleData(isFirst, rowListData, currData){
//find which one is the first iteration to add a radiobox for each row
}
renderUserData(currRow, currIdx){
return(
<div>
{chosenFields.map(this.renderChosenData.bind(this, currIdx === 0, currRow)}
</div>
)
}
render() {
return (
<div >
{PeopleData.map(this.renderUserData.bind(this))}
</div>
);
}

Categories

Resources