Get count of rows on the UI - javascript

I have a Parent component that makes an API call and passes the data to its children using a map function as the Parents API call returns an array. Now in the child component, each array result from the parent is used to make another API call. The second API call will populate the rows on the client. How do I get the count of the children rows that are shown on the clients' screen?
https://stackblitz.com/edit/rows-count has a working example, initially, the parent has an array of elements [1,2,3,4] and we are mapping each value in Parent and passing the current array value to the Child component.
In the Child component, we are checking if the passed value satisfies the value%2 === 0 condition, and based on it we are adding new values to the child's state. if the condition is satisfied we are creating a new array with the value as setHelper([value, value]) and if not satisfy the condition we are creating an array as setHelper([i*4,i*5]).
In the below example, the Parent has an array and mapping over the array to create 'n' number of children components and passing the array value as the prop to each Child. In the Child component, using useEffect and based on the value of the prop i using a state value helper and updating it to an array based on the condition.
if current value gives i%2 === 0 then the array value would be [i,i], else if we are adding [i*4,i*5] to the state and if i === 5 then we won't be displaying anything on the screen as now helper is not an array and is set to 0.
if helper is an array, we are mapping the array values inside the Child component to display.
How do I get the final count of the number of new rows in the Child component and read this value in the Parent component?
index.js
import React from 'react';
import Child from './Child'
const Parent = ()=>{
let parentState= [1,2,3,4,5]
return (
<>
<p>Parent Array is {parentState}</p>
<p>child new array is </p>
{parentState.map((i,index)=>(
<Child i={i}/>
))}
</>
)
}
export default Parent;
Child.js
import React ,{useEffect,useState}from 'react';
const Child = ({i})=>{
const [helper, setHelper]=useState(i)
useEffect(()=>{
if(i%2 === 0){
setHelper([i,i])
}else if(i == 5){
setHelper(0)
}
else{
setHelper([i*4,i*5])
}
},[])
if(Array.isArray(helper)){
return (
<>
{helper.map((i,index)=>(
<div className="child-row">
<p>-----</p>
<h4>{i}</h4>
<p>-----</p>
</div>
))}
</>
)
}
else{
return <></>
}
}
export default Child

Related

How do I create independent states for multiple copies of a react element?

New to React.
I am trying to create a set of 12 range sliders, in two columns of six. Each column is declared separately and each column independently declares the instance of the slider. Each range slider uses the package react-slider and has a currentValue state that is passed down as a prop along with the setCurrentValue method as the setState.
My issue is that when I display the values below each slider, they all sync up together, ie. they appear to all use the same variable. How do I get React to differentiate between each 'instance' as such? SliderValueText just returns an element with the value displayed.
The production value is a boolean that just tweaks the title slightly.
The Slider element:
// imports here
export const Slider = (props) => {
const { currentValue, setCurrentValue, title, production } = props
return (
<>
<ReactSlider
className='customSlider'
key={title+production}
thumbClassName='customSlider-thumb'
trackClassName='customSlider-track'
markClassName='customSlider-mark'
min={0}
max={100}
defaultValue={0}
value={currentValue}
onChange={(value) => setCurrentValue(value)}
/>
<br/>
<SliderValueText currentValue={currentValue} />
</>
)
}
The SliderSet element:
// imports
export const SliderSet = (props) => {
const { currentValue, setCurrentValue, production } = props
return (
<>
<Slider
currentValue={currentValue}
setCurrentValue={setCurrentValue}
title='Lorem Ipsum'
production={production}
/>
// 5 further slider declarations here, all identical but with different titles
</>
)
}
I have tried using the key prop and a map (below) and I have tried using an array as the currentValue state declaration in the App.js file but I cannot figure out how to use setCurrentValue with an array (below but further).
In this instance, titles is an array of all of the titles for each individual slider.
const num = 6
const nums = new Array(num)
const element = [...nums.keys()].map(i => <Slider
key={i+titles[i]+production}
usableKey={i}
title={titles[i]}
production={production}
setCurrentValue={setCurrentValue}
currentValue={currentValue}
/>)
return (
<div>{element}</div>
State Array
// App.js
const [currentValue, setCurrentValue] = useState([0, 0, 0, 0, 0, 0])
// No idea how the usage for this works
Any and all help is appreciated :)
You need to pass different values to each slider, and different functions to update that state.
Many ways to go about it. Here is one example.
export const App = () => {
const [sliderValue, setSliderValue] = useState(Array(12).fill(0));
return sliderValue.map((val, index) => (
<Slider
currentValue={val}
setCurrentValue={(newVal) => {
const newSliderValues = [...sliderValue];
newSliderValues[index] = newVal;
setSliderValue(newSliderValues);
}}
/>
));
};
When the state is an object (like this array) the internals of react determines if the object has updated by doing what's called a shallow comparison. It just checks if it's the same object or not, it doesn't examine the actual content of the object.
For that reason, when updating the array of slider values we first make a shallow copy of the array. Then update that shallow copy and finally set the state of the new array.

How to immutable update an object given that we have to pass the same object as props?

I have an object amounts that gets updated on button clicks. Ans i pass that object as a prop to another component. What i am doing right now is updating object in mutable way on button click event.
onClick = e => {
amounts.map(
amount => (amount.tax = taxes ? 500 : 0)
);
}
<Display amounts={amounts} />
How can i update amounts in an immutable way?
As mentioned in the comments, there are a few things going on:
You are not updating the amounts Array reference, so React will not re-render based on this mutation.
You are using Array#map to update a single property. This will update the Object reference in the amounts collection.
There is no setAmounts or anything similar in order to update the value of the amount property in a parent component.
Assuming you are using useState in the <Display />s parent component, you will have to pass the setAmounts function to the <Display /> component using props.
<Display amounts={amounts} setAmounts={setAmounts} />
onClick = e => {
setAmounts(
amounts.map(
amount => ({ ...amount, tax: taxes ? 500 : 0 })
);
);
}

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 to loop through object with 2 arrays?

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

Use of array.map and onchange in React

The code below contains an array.map function what is the function of term and i and where was it gotten from, and what does the array.map and the onchange do
import React, { Component } from 'react';
class Apps extends Component {
componentDidMount() {
}
iLikeFunctions() {
console.log('yay functions');
}
render() {
var array = ['here','we','go'];
var no = 'yes';
const display = 'My Name';
return (
<div>
<p>{display}</p>
<hr />
<input type="text" onChange={this.iLikeFunctions} />
<table>
<tbody>
{array.map((term,i) => {
no = 'no';
return (
<tr key={i}>
<td>{term}</td>
<td>{no}</td>
</tr>
)
})}
</tbody>
</table>
</div>
);
}
}
export default Apps;
Map:
The map() method creates a new array with the results of calling a provided function on every element in the calling array. So in the following line:
array.map((term,i)
You are mapping the array called array and looping through the array, assigning the word term for each value in the array and return a tr element for each array element with their respective value, index and variable string printed on the <tr>.
Key:
i is the index of the respective value which acts as a key since you didn't specify unique key ids for the elements.
A "key" is a special string attribute you need to include when creating lists of elements. Keys help React identify which items have changed, are added, or are removed.
Do note that it is not recommended to use indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state.
Check out the keys section in the official React Docs for a more in-depth explanation of keys.
onchange:
onchange watches the input field for any change and when it detects a change, it runs the iLikeFunctions().
tldr: The above code loops through array ['here','we','go']; and returns a <tr> for each value. It also runs the iLikeFunctions() whenever the input field value is changed.

Categories

Resources