Multiple map functions and returning HTML - reactjs

I'm running into issues with multiple map functions and displaying data. I believe I'm missing some returns in the appropriate spots, but can't find a good example online. Any help is appreciated. Thanks!
Object.keys(patternData).map((pattern) => {
if (patternData[pattern]['Matches'] && Object.keys(patternData[pattern] ['Matches']).length !== 0) {
Object.keys(patternData[pattern]['Matches']).map((matchSymbol) =>
<p> {matchSymbol} </p>
)
}
})

Related

Get access to an array in an array from REST API

Hi I'm trying to display variants in two separate categories Color and Size, to do this I need to get data from the api, I can access "attributes", but I would like to be able to access 0 and 1 and map them, I have no idea how to do this.
{variants.length > 1 ? (
variants.attributes.map(({ name, values }) => (
<ProductOptions
key={`key-${name}`}
name={name}
values={values}
selectedOptions={selectedOptions}
setOptions={setOptions}
/>
))
) : (
<Fragment />
)}
Thank you so much!
As i understand the output of Array with 6 elements where each of that 6 has attributes and attributes is yet another array and you want to loop through those attributes so you need 2 loops. One to loop through parent array and seconds inside the child.
variants.map((variant) => {
variant.attributes.map((attribute) => {
console.log('attribute: ', attribute);
console.log('attribute id: ',attribute.id);
});
});
p.s. you may use forEach https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach but it has little difference in this case.
Also it seems like you working with ReactJS and building some JSX to put into rendered jsx. I would argue to form the array upfront and in final jsx just insert the rows, so your final jsx will be more readable, especially in cases of double loops or any more complex jsx.
const attributes = [];
variants.map((variant) => {
variant.attributes.map((attribute) => {
console.log('attribute: ', attribute);
console.log('attribute id: ',attribute.id);
attributes.push(<div key={attribute.id}>{attribute.id}</div>)
});
});
// later
return (
<div>
{attributes}
</div>
)

React hooks boolean in state not properly being set

I apologize but I could not find an answer that helps with my problem.
I'm making a pokemon 20 questions game and recently added a new question to ask.
I'll do my best to keep it clear. But every answer is stored in state
Like this:
const [type, setType] = useState(null);
const [weakness, setWeakness] = useState(null);
const [evolve, setEvolve] = useState(null);
etc.
So I have buttons set up that assign these values as a user progresses through the game.
But my evolve question breaks the game.
Here is the function
const evolveAssign = (canEvolveBoolean) => {
setEvolve(canEvolveBoolean);
setPokemonData((prevPokeArray) => // pokemon data is a giant array of pokemon objects
prevPokeArray.filter((pokemon) => {
if (canEvolveBoolean === true) {
return pokemon.prev_evolution || pokemon.next_evolution; //checks if the properties exist. Pokemon that do not evolve, do not have such properties.
} else {
return !pokemon.prev_evolution && !pokemon.next_evolution;
}
})
)};
This is how it is being returned. Which I admit, I'm not sure if this is the best way to display questions.
{type && weakness && !evolve && (
<div>
<strong>Can your Pokemon Evolve?</strong>
<EvolveBtn mapEvolutions={mapEvolutions} onClick={evolveAssign} />
</div>
)}
The problem
When the user hits 'No' it will pass false to the function, and it does seem to work! But the question gets stuck only on "No" So I logged
<p>evolve = {evolve}</p>
and it will show 'evolve = '. So somehow, evolve is not being set at all? I haven't had this issue before with the other questions.
Is there something weird going on because it's a Boolean? Is my JS logic bad? I'm pretty much out of ideas. I apologize if this was unclear/messy. I'd love any feedback as I'm still learning.
Thank you very much.
EDIT: Created a Codesandbox here!
https://codesandbox.io/s/damp-bush-u6yel?file=/src/App.js
The error can be seen if you choose Bug -> Fire -> "No". It will break after that.
I took a look at the sandbox. Several things can be improved but I will just focus on the evolve issue.
In JavaScript null and false are falsy values. !null or !false will return true. This is why the questions are rendered incorrectly after selecting evolve.
A quick and easy fix would be to check if evolve is null or the opposite if the user already selected evolve.
{
type && weakness && (evolve === null) && (
<div style={{ fontSize: 50 }}>
<strong>Can your Pokemon Evolve?</strong>
<EvolveBtn mapEvolutions={mapEvolutions} onClick={evolveAssign} />
</div>
)
}
{/* What height? */ }
{
type && weakness && (evolve !== null) && !height && (
<div style={{ fontSize: 50 }}>
<strong>Select Height</strong>
<HeightBtn mapHeight={mapHeight} onClick={heightAssign} />
</div>
)
}
Similar checks need to be used in the rest of the conditions if you simply want to make the app work.

React Native - Is using Immer.js and SetState together a problem?

Yesterday I had a behaviour that I don't understand by using Immer.js and setState together. I was using a setState (in a bad way, by the way) when fetching my data and this fetch was called at each endReached of my SectionList.
This setState looked like this:
this.setState((prev) => {
let sections = prev.sections
/* Extract alive topics from "topics"(array retrieved from fetch)*/
let topicsSection1 = topics.filter((card) => !card.states.is_killed)
/* Extract killed topics from "topics"(array retrieved from fetch)*/
let topicsSection2 = topics.filter((card) => card.states.is_killed)
if (sections[0] && sections[0].data)
sections[0].data = positionExtracted > 1 ? sections[0].data.concat(...topicsSection1) : topicsSection1
if (sections[1] && sections[0].data)
sections[1].data = positionExtracted > 1 ? sections[1].data.concat(...topicsSection2) : topicsSection2
return {
sections: sections,
position: response.position,
lastPage: response.laftPage
}
})
and everything worked just fine.
However, I have a function that is called when you press on the topic, and it changes the "opened" value of the topic in the data array to indicate to the list that "this topic" is open.
This function calls the "produce" function of Immer.js
And this function looks like this:
_onPressTopic = (id_card) => {
this.setState(produce((draft) => {
if (draft.sections[0] && draft.sections[0].data)
draft.sections[0].data = draft.sections[0].data.map((item) => {
if (item.id === id_card)
item.opened = !item.opened
return item
})
if (draft.sections[1] && draft.sections[1].data)
draft.sections[1].data = draft.sections[1].data.map((item) => {
if (item.id === id_card)
item.opened = !item.opened
return item
})
}))
}
MY PROBLEM IS:
If I open a topic and then my list data goes through this function, then when an endReached is called again, either I get an error "This object is not expensive", or my list data is not modified at all. And if instead of my first setState, I use a produce from Immer, everything works again.
What I don't understand is: Why does everything work perfectly if I only use Immer.js or just SetState, but as soon as I try to use both together, they don't seem to get along?
Thank you for your answers,
I hope I made it clear !
Viktor

In Cypress to test getting total number of elements from listbox and then according to the data run in loop and as per each data perform an if

In Cyress Test writing an test of react application when I click on a Listbox in the drop down it get list of data.
eg : 123a, 1233, 111c etc suppose have count 50
then select each 1 by 1 however need to compare each that if its certain account perform certain checks
in details:
have searched and clicked the listbox but the issue i am facing how can i find the total number of elements in that listbox and need to traverse each item/value 1 by 1 and when select verify certain asserts.
so 3 challenges where i am stuck
1) How to get total number of elements have tried initial count=cy.get('#alias').length seems not working.
2) after we get how can I iterate through the loop 1 at a time as after selecting 1 item as have to certain assertions.
Thanks
Varun Awasthi
First:
cy.get("alias").length can never work because of the async structure of cypress. The get() returns never the wrapped element but a chainable. Thus you would have to write something like get(..).then(obj => ...)
Second:
Given this HTML structure:
<div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
</div>
You can get the length ( = the mount of item elements) like this:
it("test", () => {
cy.get(".item").should($items => {
cy.log(`amount: ${$items.length}`)
})
})
Third:
Please try something like this:
it("test", () => {
cy.get(".item").each($item => {
cy.wrap($item).should($e => {
expect($e.text()).to.eq("test")
})
})
})
But you must not use cypress commands here. Something like this should also work:
cy.get(".item").should($items => {
for(var i = 0; i < $items.length; i++) {
expect($items[i].text()).to.eq(...)
}
})
So you can also work with a combination of cypress commands and jQuery.
Let me know if you need furhter assistance
I am new to this, but to get the count of elements returned I would use something like this:
cy.get('.item').its('length')
Then, if you want to work with specific elements from that array:
.then(size => {
for(i= 0; i < size: i++) {
cy.get('.item').eq(size).should('have.value', 'list item')
}
})

Printing data from array using shorthand

I am using react-admin framework and I am trying to print data from my array.
My array is looking like this:
enter image description here
As you can see it currently has 3 indexes. Each of them stores different data. I want to print these data on to same page.
I am aware that I need to use some sort of cycle (for, foreach), but I really dont know how to implement it in shorthand.
This is my code, that I need to loop:
ID: {this.state.source[index].Id}<br></br>
AuditDate: {this.state.source[index].AuditDate}<br></br>
UserId: {this.state.source[index].UserId}<br></br>
Resource: {this.state.source[index].EntitySet}<br></br>
Entity1: {this.state.source[index].Entity1}<br></br>
Entity2: {this.state.source[index].Entity2}<br></br>
Operation: {this.state.source[index].Operation}<br></br>
EndPoint: {this.state.source[index].EndPoint}<br></br>
Changes: {this.state.source[index].Changes}<br></br>
Any ideas how to loop this?
Thank you in advance
You can make use of map to iterate over array,
{
this.state.source && this.state.source.length > 0 && this.state.source.map(source => {
return <>
<div>ID: {source.Id}</div>
<div>AuditDate: {source.AuditDate}</div>
<div>UserId: {source.UserId}</div>
<div>Resource: {source.EntitySet}</div>
<div>Entity1: {source.Entity1}</div>
<div>Entity2: {source.Entity2}</div>
<div>Operation: {source.Operation}</div>
<div>EndPoint: {source.EndPoint}</div>
<div>Changes: {source.Changes}</div>
</>
})
}
renderSources() {
const sources = source.map((eachSource) => {
return (
<div>
<span>`ID: ${eachSource.Id}`</span>
<span>`AuditDate: ${eachSource.AuditDate}`</span>
<span>`UserId: ${eachSource.UserId}`</span>
<span>`Resource: ${eachSource.EntitySet}`</span>
<span>`Entity1: ${eachSource.Entity1}`</span>
<span>`Entity2: ${eachSource.Entity2}`</span>
<span>`Operation: ${eachSource.Operation}`</span>
<span>`EndPoint: ${eachSource.EndPoint}`</span>
<span>`Changes: ${eachSource.Changes}`</span>
</div>
);
});
return sources;
}
render() {
return (<div>{this.renderSources()}</div>);
}

Resources