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>
);
}
Related
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
Hello I am new to programming and I am trying to make a function in React that adds a team to an array of selected teams but only if there are less than 2 teams selected and if the team is available (not already chosen). It is working to limit the array to only 2 values but the array will accept the same team twice and I am not sure why. For example if the user clicks ATL twice then that team will be in the array twice. What did I do wrong here and what should I change in order to fix it? Sorry if the question is too simple for this forum, I am new.
Here is the code where I am changing the state and checking if gameState.selected_teams[0] != team:
function App() {
const [gameState, setGameState] = useState({
cards: Cards,
selected_teams: []
});
function setTeam(team){
if (gameState.selected_teams.length < 2 && gameState.selected_teams[0] != team) {
setGameState((prevState) => ({
cards: prevState.cards,
selected_teams: [
...prevState.selected_teams, {
team
}
]
}))
}
}
And for the component that calls the setTeam function:
function TeamSelect({cards, setTeam}) {
var teams = Object.keys(cards);
return (
<div className='flex-container'>
<div className='team-container'>
{
teams.map(team => (
<div
onClick={() => setTeam(team)}
className='team-label' key={team}>
{team}
</div>
))
}
</div>
</div>
)
}
You're adding an object {team: team} to your selected teams array each time you perform your click here:
selected_teams: [
...prevState.selected_teams, {
team
}
]
but your team key that you pass into your setTeam function is a string, so your comparison fails as you're trying to compare a string with an object. You can change your comparison to extract the team property from your object:
gameState.selected_teams[0]?.team != team
The ? ensures that a value exists at index 0 in your array before using .team on it (otherwise you would get an error if it's undefined).
You can adapt this code to handle more than one object by using .every() to check that all objects in selected_team's aren't equal to the one you're adding:
if(gameState.selected_teams.length < 2 && gameState.selected_teams.every(obj => obj.team != team)
If you don't need to pass an object {team: team} (as an object with one property doesn't add much value), then you can simply push your team string into your selected teams, and use .includes() to check if the team you're adding already exists in the array:
selected_teams: [
...prevState.selected_teams, team
]
you can then update your condition to use .includes():
if(gameState.selected_teams.length < 2 && !gameState.selected_teams.includes(team))
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
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>
)
})
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.