React save the value of current state and make it unchangeable - reactjs

I am new to React and I have a problem considering saving the value of current state. I am not sure if it is possible.
To summarise, I have build up a function which returns a HTML element as below. The idea is to save a div on each click.
createQuestion(){
let CurrentQuestion=this.state.freetextinput;
return this.state.values.map((el, i) =>
<div key={i} className="QuestionBox">
{CurrentQuestion}
</div>
)
}
The value of freetextinput changes on each click. The idea is to save all the value of freetextinput. Say, the values of freetextinput are 1, 2, 3. I would like to have all of the three values:
1
2
3
However, I only get something like this:
3
3
3
I wonder, if there is a way to save/store the value of this.state.freetextinput, such that I can get all the three values.

The new question needs to be pushed into an array before it can be mapped. Might something like this work for you?
var savedQuestions = []
createQuestion(q){
savedQuestions.push(q)
this.setState({savedQuestions: savedQuestions}, () => {
var questionElements = this.state.savedQuestions.map((el, i) =>
<div key={i} className="QuestionBox">
{el}
</div>
)
})
return questionElements
}

Save every input of free text input into an array, that way you would get access to all the values:
You can check this code sandbox: https://codesandbox.io/s/j835121kv

You should map this.state.freetextinput directly :
Since freetextinput is a string, you will need to convert it to an array first using split
createQuestion(){
return this.state.freetextinput.split(', ').map(el =>
<div key={el} className="QuestionBox">
{el}
</div>
)
}
This will work if your string looks like : "1, 2, 3"
If your string is "123" then use split('') instead of split(', ')

Related

React - how to 'split' an array to give line breaks

I have an array, let's say:
["One", "Two", "Three"]
And I'd like to render it as a string on separate lines with "<br/>" between each element as:
One<br/>Two<br/>Three
so that they'll render as separate lines. What I'd use in a text-based system would be something like:
my_array.join("\n")
So what I want is the equivalent of:
my_array.join(<br/>)
But that doesn't work in something like:
return <div>{my_array.join(<br/>)}</div>;
as it returns objects instead of what I'm looking for:
One[object Object]Two[object Object]Three
Note that I DON'T want a trailing <br/> at the end - I understand I could use a map for that.
To save you reading further, the solution I used is:
my_array.map((item, index) => index ? <><br/>{item}</> : <>{item}</>)
which does use a map but utilises the index to place a <br/> before every element but the first.
Something like this should work:
["One", "Two", "Three"].map((item, index) => {
if (index === 0) {
return <>{item}</>
}
return <><br/>{item}</>
})
I think you can edit the each string array value and put the line break in to it .
you need to use map function.
<div>{my_array.join.map((item, index) =>
<span> {item}<br/></span>
)}</div>
This is how you would do it:
function MyComponent(props) {
let arr = ["One", "Two", "Three"];
return (
<div>
{[...arr.map(item => <div key={item}>{item}</div>), <br key={'br'}/>]}
</div>
);
}
export default MyComponent;
Don't forget that it is important to include a unique key prop for each element in the array to ensure that React can efficiently update the list.
Hope it helped!

Dynamic element from array

I want to dynamically update a element whenever the array it is based from changes.
//Dynamic Array - depositInfo[0] looks like:
//[{"tsR":1648183525,"durR":30,"amtR":10000000000000000}]
let depositInfo = [];
const depositCard = (card, index, amtR) => {
return (
<div key={index}>
<Text strong>
Value that doesn't update!:
{card.tsR}
{parseFloat(card.tsR)}
{JSON.stringify(depositInfo[index].tsR)}
<p />
Values that do update!:
{JSON.stringify(depositInfo[index])}
<p />
</Text>
</div>
);
};
The element is rendering on the page before the values are dynamically retrieved into the array, rendering it blank. After the array updates, the values on the page remain the same except for the ones generated by {JSON.stringify(depositInfo[index])}
How do I update the depositCard info every time depositInfo[] changes/is updated?
Edit:
Also why does depositInfo[index].tsR return a blank value when depositInfo[index] works fine?

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

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

Conditional classes on single instances of component within a loop

I have a loop of components that make a grid and I want some instances to have a background color change triggered by adding a class.
This question gave me ideas but I've yet to get them to work.
I have this basic markup in it.
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
And I have an array of the indexes representing the component instances that I want the color changed on
let indexes = [101, 178, 232, 545]
Currently I am doing it with plain JS, via document.querySelector('.box:nth-of-type(101'), but as this method bypasses React I want to change it.
Based on the other question I tried making an array of all the components and setting that to state, then looping through and using the indexes. I don't know how to "access" the component like this and get $$typeof: Symbol(react.element) etc
let compArr = []
this.arr.map((i) => {
compArr.push(
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
)
})
this.setState({
compArr: compArr
})
Then later loop over indexes:
indexes.map(index => {
this.state.compArr[index] ===> ??stuck here??
})
Expected Output: So on an array of three instances, say I want the second one only to have the class of backgroundColor:
<div className='box' </div>
<div className='box backgroundColor'</div>
<div className='box'</div>
Only in my case, I want the instances to correlate with the indexes array
How can I set the conditional class to true in those instances I have in the array? Say I have like 500+ instances total.
If I understand you correctly this is proably what you're looking for...
let indexes = [101, 178, 232, 545]
let compArr = this.arr.map((obj, i) => {
return (
<div
className={`box${( indexes.includes(i) ? " backgroundColor" : "")}`}
key={i}
>
</div>
);
})
this.setState({
compArr: compArr
})
If your goal is only to return the given div with the className backgroundColor for every element in this.arr with its index included in the indexes array then...
You only need to iterate over the array once and can perform all the necessary logic you're currently doing performing in two.
You don't need to use Array.push() to an outside collector when using any of the pure functions like map() or reduce() because they return a new version of whatever array is iterated over.
If for whatever reason you want a distinct array of <div>s with an index in indexes then you should use reduce...
let compArr = this.arr.reduce((acc, obj, i) => {
if (!indexes.includes(i)) return acc;
return [
...acc,
<div className="box backgroundColor" key={i}></div>
)]
},[])

Resources