How can I use break to break a .map() function when condition rendering is true ?
This is my example code
{messages.length >= 1 ? (
<div>
{messages.reverse().map((e) => (
e.senderName[0] == displayName[0] ? (<p>Status: {e.message}</p>) : null
))}
</div>
) : (<p>Status: Verifying...</p>)}
The problem is in messages array is gonna have a new message add every 60 second and I want to display a new message on my screen that has been add in every 60 second
Then I want to break .map() function after a new message has been add to messages array and display on my screen
What I want is like this enter image description here
But the problem is like this enter image description here
you can't use break to stop .map() method. I see that you are trying to render messages if message belongs to current user.
I can recommend you to filter the messages first, then render the filtered array with mapping. Like:
const usersMessages = messages.reverse().filter((e) => (e.senderName[0] === displayName[0]);
return (
<div>
{usersMessages.length > 0 ? (usersMessages.map(e =>{
return((<p>Status: {e.message}</p>))
})) : <p>Status: Verifying...</p>)}
</div>
)
Of course you must have a part in your code that updates the messages array and triggers a re-render when data is updated.
Related
I'm working on a time tracking dashboard project using Css Grid and vanilla JS, which has different activity cards that display the current and previous week's hours pulled from a json file and with an event listener, but i'm struggling with the JS logic. I'm able to fetch and loop through the json data using async await, and able to log the data in the console, so the call is definitely working, but i am unable to get the data to display properly in the activity cards using .innerHTML().
Image of console showing correct data with innerhHTML and event listener
The problem is that even with the data showing in the console I am unable to display that information in the cards. I am using forEach to loop through each stat in the Json file, and have tried experimenting by adding another loop for the card sections, but this just results in the same stat being duplicated on each card. This is a fairly simple one, but i'm a bit stuck on it.
I also recognise that my code could be much more DRY, any pointers for reducing the repetition for each time duration
statBtn.addEventListener("click", (e) => {
const activities = document.querySelectorAll(".previous-activity");
console.log(activities);
const id = e.target.id;
console.log(id);
if (id === "daily") {
btnStyles("daily");
getData().then((stats) =>
activities.forEach((activity) => {
console.log(activity)
return activity.innerHTML = `
<p class='curr-hrs'> ${stat.timeframes.daily.current} hrs</p>
<p class='previous-hrs'>Last Week - ${stat.timeframes.daily.previous} hrs</p>`;
});
})
);
} else if (id === "weekly") {
btnStyles("weekly");
getData().then((stats) =>
activities.forEach((activity) => {
console.log(activity)
return activity.innerHTML = `
<p class='curr-hrs'> ${stat.timeframes.weekly.current} hrs</p>
<p class='previous-hrs'>Last Week - ${stat.timeframes.weekly.previous} hrs</p>`;
});
})
);
} else if (id === "monthly") {
btnStyles("monthly");
getData().then((stats) =>
stats.map((stat) => {
console.log(`${stat.timeframes.monthly.previous} hours`);
// console.log(activity);
return activities.innerHTML = `
<p class='curr-hrs'> ${stat.timeframes.monthly.current} hrs</p>
<p class='previous-hrs'>Last Week - ${stat.timeframes.monthly.previous} hrs</p>`;
console.log(activities.innerHTML);
);
}
})
);
Any help will be appreciated!
thanks,
Evan
"activity" is more than 1 element. innerHTML should target 1 element (https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)
Clean up:
a. Create a switch case for adding button styles
b. Your request for data seems identical, so you may want to create an individual function for that
Extra: please note there's typo's in the second and third return statement (activities instead of activity)
Introduction
I have a search filter in which I enter parameters such as sender and recipient.
In this way for the sender I make a call and get results.
For the recipient I make another call and get other results.
So I will have two arrays:
sent
sent1
what I would like to do is iterate through the first arrival comparing each element with each element of the second array and if a certain condition is exceeded save the element of the first array.
Now my Code is:
let filteredSent = {rows: []}
sent.rows.map( (elem) => { sent1.rows.find( (value) => {
if(value.key[2] === values.recipient.Code && value.key[0] === "RECIPIENT" && elem.key[1] === value.key[1] && elem.key[3] === value.key[3] && elem.value === value.value){
filteredSent.rows.push(elem)
}
})
} )
where values.recipient.Code is an input value that I choose from a list.
My problem is that I make this comparison, but I find myself certain results that shouldn't be there.
Is what I'm doing the map and find a wrong use?
Thank you all for your time.
I'm updating an object within react's state which I use to display a list. The state updates correctly, however the display breaks.
This is the section of the code from inside my render function which produces the list.
this.state.shoppingItems ? this.state.shoppingItems.currentShoppingItems.map((item, index) => {
console.log(item)
return <ItemSummary key={index} onClickHandler={this.selectItem} updateShoppingItem={this.updateCurrentShoppingItem} shoppingItem={item} removeFromCurrentItems={this.removeFromCurrentItems} addToCurrentList={this.addToCurrentList} />
}) : undefined}
Here is the code that produces the previous items list:
this.state.shoppingItems ? this.state.shoppingItems.previousShoppingItems.map((item, index) => {
console.log(item)
return <ItemSummary key={index} onClickHandler={this.selectItem} updateShoppingItem={this.updateCurrentShoppingItem} shoppingItem={item} removeFromCurrentItems={this.removeFromCurrentItems} addToCurrentList={this.addToCurrentList} />
}) : undefined}
This is the method which removes the item from the current list and adds it to the previous list, where the issue occurs.
removeFromCurrentItems(shoppingItem) {
const items = this.state.shoppingItems.currentShoppingItems.filter(item => item._id !== shoppingItem._id);
let shoppingItems = this.state.shoppingItems;
shoppingItems.currentShoppingItems = items;
shoppingItem.number = 0;
shoppingItem.completed = false;
shoppingItems.previousShoppingItems.push(shoppingItem);
this.setState({
shoppingItems: shoppingItems
});
// call to API to update in database
}
Here is the list before I remove the item.
Here is the list after I remove the middle item:
Finally here is the console.log output which shows that the items have updated properly but the display hasn't updated:
I'm entirely new to react coming from angular so I have no idea if this is the correct way to do this or if there is a better way. But could somebody help me figure out why the display isn't updating?
The issue seemed to be the key on the item in the map. I replaced the index with the item's id from the database as below and now it renders properly.
return <ItemSummary key={task._id} updateShoppingItem={this.updateCurrentShoppingItem} shoppingItem={task} removeFromCurrentItems={this.removeFromCurrentItems} addToCurrentList={this.addToCurrentList} />
Similar answer here:
Change to React State doesn't update display in functional component
The issue is the update for shoppingItems. You save a reference to the current state object, mutate it, and store it back in state. Spreading this.state.shoppingItems into a new object first will create a new object reference for react to pick up the change of.
React uses shallow object comparison of previous state and prop values to next state and prop values to compute what needs to be rerendered to the DOM and screen.
removeFromCurrentItems(shoppingItem) {
const items = this.state.shoppingItems.currentShoppingItems.filter(item => item._id !== shoppingItem._id);
const shoppingItems = {...this.state.shoppingItems};
shoppingItems.currentShoppingItems = items;
shoppingItem.number = 0;
shoppingItem.completed = false;
shoppingItems.previousShoppingItems.push(shoppingItem);
this.setState({
shoppingItems: shoppingItems
});
// call to API to update in database
}
I had a similar issue with my application in which I had to delete comments made.
<textarea disabled key={note._id} className="form-control">{note.note}</textarea>
But the issue got resolved when I added the Key attribute to the list item.
I have a React Native form that allows me to add an Input UI in the form, by clicking a button with this function. This allow me to generate it on the fly. The code for that is this.
addClick() {
this.setState(prevState => ({ values: [...prevState.values, ""] }));
console.log(this.values[0].name);
}
That part works well, but I'm having a problem extracting the data from the dynamic inputs, and add it to an array. So far I have tried this
setVal = value => {
const values = this.state.values[0];
if (values[0].name === "" || values[0].description === "") return;
[...this.state.values, value];
this.setState(values);
console.log(values);
};
How do I organize my states properly so that I can add as many inputs I need, and when I'm finished, I can update the state, and access the new data in my list component?
How do I update my state to the new Array? at the moment, this.state only shows the initial state set at the top.
I'm missing a few things
Please take a look at the full code sandbox HERE so you can see:
See...your created isssue is not so obvious we need to see where you call setVal() function but....
i think you will be more comfortable if you render your <input/> s directly from your state array, not from const x = [] variant. because it seems like you want a dynamic view and in such a cases you will need to bind your loop quantity from state. so:
this.state = {
x: [0,1,2,3,4]
}
and inside your render :
{this.state.x.map(x => {
return (
<TextInput
placeholder={`name${x}`}
value={values[x.toString()]}
handleBlur={() => handleBlur(x.toString())}
onChangeText={handleChange(x.toString())}
style={styles.input}
/>
);
})}
I am building a test app to learn more about React and I have made an API call which gets a huge JSON object.
I was able to break this json into the parts that I need and now I have 10 arrays of 3 props each. I am able to send these 10 arrays in 3 props to another component, which needs to use these 3 props 10 times and render a div class Card each.
I can console.log(this.props) and it shows 10 different arrays with 3 props each,however, I cannot produce a same element 10 times.. I tried using map() but since my array is initially undefined, map() is not able to function properly either. Is there any thing in react like *ngFor in Angular ?
What is the best way to go about this?
*EDIT
Here's more code guys. Sorry still noobie here..
ERROR : this.props.map is not a function
return(
<div>
{this.props.map((data,i)=>{
return(
<li key={i}>{data.likes}</li>
);
*EDIT 2
Soo I tried running map function with an if condition but the code still breaks the very moment the condition gets true..
render() {
if(this.props.url !== undefined){
this.props.map((data,i) =>{
return <li key={i}>{data.likes}</li>
})
}
My state method is :
state = {
userId: undefined,
likes: undefined,
url: undefined
}
and im setting my values on each data stream as follows :
const pics = await fetch(`${base_url}?key=${api_key}&q=${query}
&img_type=photo&per_page=12`).then(response => {
return response.json();
})
pics.hits.map((data) =>{
return this.setState({
userId: data.user_id,
likes: data.likes,
url: data.webformatURL
})
})
this.props won't have map, it's not an array. It's an object with a property for each property passed to your component. For instance:
<YourComponent foo="bar"/>
...will have this.props.foo with the value "bar".
So if you're passing an array to your component, like this:
<YourComponent theArrayProperty={[{likes: 42},{likes:27}]} />
...then you need the name of that property:
return (
<div>
{this.props.theArrayProperty.map((data,i) => {
return (
<li key={i}>{data.likes}</li>
);
})}
</div>
);
Side note: You can use a concise arrow function for the map callback instead:
return (
<div>
{this.props.theArrayProperty.map((data,i) => <li key={i}>{data.likes}</li>)}
</div>
);
...and no need for the () if you put the opening tag on the line with return (you can't leave off the ( if it's on the next line, but you probably knew that):
return <div>
{this.props.theArrayProperty.map((data,i) => <li key={i}>{data.likes}</li>)}
</div>;
...but that's a matter of style.
With little information that you have provided, my guess is that code fails at map() when you try to use it with undefined value.
Try adding a conditional check to render
{props && props.map([RENDER CODE HERE])}
You can just make simple if statement to check if the array is not undefined, and then pass it to map function.
Another option is to set a defaultProps for an empty array.
MyComponent.defaultProps = {
arrProp: []
};