Chat map with react js, objects inside array - javascript

I'm trying to make a basic chat.
I want that for every contact I could save the messages from the both users and show them on the screen (just like chat in whatsapp web).
My code:
const [chatArr , setChatArr] = useState([
{
id: "v7fAa5OltrU=",
from: "Shai Dayan",
newMsg:{
msgs: [
{sender: 0, text:"Hello there, I'm using Chat !"},
{sender: 1, text:"Hello there, I'm using Chat !"}
]
},
group: false,
players: ['Shai Dayan']
},
And I'm trying to map this texts like this:
{chatArr[fullChat].newMsg.msgs.map((element,index)=>{
return <div className='speech-bubble'>
<div className="text-msg">
<div className='name-msg'>
<span className='from'>{chatArr[fullChat].from}</span> <br/>
{element.text}
</div>
<div>
</div>
</div>
</div>
})}
but it is not working..How can I make a array of objects that each object will contain the sender and the text and map it by the order?

From the array you posted here is how you can map over it.
You need to have a nested map, first to map over your chats and then to map over each message in the chat
{
chatArr && chatArr.map((chat,index) => {
return (
<>
{
chat.newMsg.msgs.map((msg,idx) => {
return (
<div className='speech-bubble'>
<div className="text-msg">
<div className='name-msg'>
<span className='from'>{chat.from}</span>
<br/>
{msg.text}
</div>
</div>
</div>
)
})
}
</>
)
}
}

Related

Only getting objects set to true to display in component (React)

I have two React components.
The first one is just an export of an array that holds multiple objects.
VideoGameList.js
const VideoGameList = [
{
id: 1,
title: "Fire Emblem Engage",
src: vg01,
releaseDate: "01/20/2023",
price: 59.99,
quantity: 1,
inCart: true,
},
{
id: 2,
title: "Pokemon Violet",
src: vg02,
releaseDate: "11/18/2022",
price: 59.99,
quantity: 1,
inCart: false,
},
];
And the second one is a shopping cart
ShoppingCart.js
const ShoppingCart = (props) => {
return (
<>
<Header />
{VideoGameList.inCart === false && (
<div>
<h1 className="sc-empty-title">Your Shopping Cart Is Empty!</h1>;
<div className="shopping-cart-image">
<img src={shoppingCart} alt="empty-cart-image"></img>
</div>
</div>
)}
{VideoGameList.inCart ===
true(
<div className="videogame-content">
{VideoGameList.map(
(
{ id, title, src, releaseDate, price, quantity, inCart },
index
) => (
<div className="videogame">
<img key={src} src={src} alt={title} />
<div className="title-date">
<p className="title">{title}</p>
<p className="date">{releaseDate}</p>
</div>
<div>
<p className="price">${price}</p>
<button className="console">Add to Cart</button>
</div>
</div>
)
)}
</div>
)}
</>
);
};
export default ShoppingCart;
Under the VideoGameList object you'll notice a value of inCart set to either true or false. Using conditional render I'm trying to make it so if all inCart object values are set to false, the shopping cart will be (technically) empty and an image will be displayed. But if even a single inCart object value is set to true, that image will be displayed in its own div and the empty shopping cart image will not be displayed. However, my code appears to be wrong as when I go to the ShoppingCart page the only thing that is displayed is the Header and everything underneath is a white screen. Everything that I've tried doesn't appear to be working. Please advice.
It will be clearer and a little more efficient to reverse your logic, and check if some() of your objects are in the cart first. This has the advantage of stopping early if there is an element in the cart, instead of having to always check every element in the array. It is also much clearer to test a positive condition rather than a negated one — 'if any is true...' vs 'if every is not true ...'
To only map those elements that are in the cart you can add a filter before your map() call (if you are doing other things with the objects in the cart it may be worth handling this filtering earlier in the component or storing in state at some level).
<>
<Header />
{VideoGameList.some(v => v.inCart)
? (
<div className='videogame-content'>
{VideoGameList.filter(v => v.inCart).map( // filter before mapping ({ id, title, src, releaseDate, price, quantity, inCart }, index) => (
<div className='videogame'>
<img key={src} src={src} alt={title} />
<div className='title-date'>
<p className='title'>{title}</p>
<p className='date'>{releaseDate}</p>
</div>
<div>
<p className='price'>${price}</p>
<button className='console'>Add to Cart</button>
</div>
</div>
),
)}
</div>
)
: (
<div>
<h1 className='sc-empty-title'>Your Shopping Cart Is Empty!</h1>;
<div className='shopping-cart-image'>
<img src={shoppingCart} alt='empty-cart-image'></img>
</div>
</div>
)}
</>;
VideoGameList.inCart is undefined that's why doesn't catch none of your conditions. VideoGameList is an array of objects and you can't access it like that. For example this will work, but is not dynamic and doesn't help in your case VideoGameList[0].inCart. I would suggest to use
VideoGameList.every((v) => v.inCart // this will return for every object in array his inCart value

With React, what is the best way to pass a useState array back and forth between components?

I had some help with a previous issue with my little project, but I have a new problem I can't seem to understand. My program takes an array of objects (call them cards), and displays an on-screen card for each element in the array. I have an edit button for each card, which should open the edit form for the chosen item, and pre-populate it with its current state - this all works.
I want to be able to edit the item, save it back in place into the array, and have that 'card' updated. This is the main component:
import React from "react";
import ReactFitText from "react-fittext";
import Editform from "./Editform";
function Displaycards({ lastid }) {
// dummy data hardcoded for now
const [cards, setCards] = React.useState([
{
id: 1,
gamename: "El Dorado",
maxplayers: 4,
freespaces: 1,
tablenum: 5,
},
{
id: 2,
gamename: "Ticket to Ride",
maxplayers: 4,
freespaces: 2,
tablenum: 3,
},
]);
const [showForm, setShowForm] = React.useState(false);
const [currentid, setCurrentid] = React.useState(0);
return (
<div className="cardwrapper">
{cards.map(({ id, gamename, maxplayers, freespaces, tablenum }) => {
return (
<div key={id}>
<div>
<div className="card">
<ReactFitText compressor={0.8}>
<div className="gamename">{gamename}</div>
</ReactFitText>
<div className="details">
<p>Setup for: </p>
<p className="bignumbers">{maxplayers}</p>
</div>
<div className="details">
<p>Spaces free:</p>
<p className="bignumbers">{freespaces}</p>
</div>
<div className="details">
<p>Table #</p>
<p className="bignumbers">{tablenum}</p>
</div>
<button type="button" className="playbutton">
I want to play
</button>
<br />
</div>
<div className="editbuttons">
<button
type="button"
className="editbutton"
onClick={() => {
setShowForm(!showForm);
setCurrentid(id);
}}
>
Edit
</button>
<button type="button" className="delbutton">
X
</button>
</div>
</div>
</div>
);
})}
{showForm && (
<div>
<Editform cards={cards} setCards={setCards} id={currentid} />
</div>
)}
</div>
);
}
export default Displaycards;
and this is the Editform.js which it calls at the bottom. As far as I can tell I'm passing my array, setter function, and id of the card I want to edit:
function Editform({ cards, setCards, id }) {
const thisCard = cards.filter((card) => card.id === id)[0];
const editThisCard = thisCard.id === id; // trying to match id of passed card to correct card in 'cards' array.
console.log(editThisCard);
function saveChanges(cardtochange) {
setCards(
cards.map(
(
card // intention is map back over the original array, and if the id matches that
) =>
card.id === id // of the edited card, write the changed card back in at its ID
? {
id: id,
gamename: cardtochange.gamename,
maxplayers: cardtochange.maxplayers,
freespaces: cardtochange.freespaces,
tablenum: cardtochange.tablenum,
}
: card // ... or just write the original back in place.
)
);
}
return (
<>
{editThisCard && ( // should only render if editThisCard is true.
<div className="form">
<p>Name of game:</p>
<input type="text" value={thisCard.gamename}></input>
<p>Max players: </p>
<input type="text" value={thisCard.maxplayers}></input>
<p>Free spaces: </p>
<input type="text" value={thisCard.freespaces}></input>
<p>Table #: </p>
<input type="text" value={thisCard.tablenum}></input>
<p></p>
<button
type="button"
className="playbutton"
onClick={saveChanges(thisCard)} //remove to see edit form - leave in for perpetual loop.
>
Save changes
</button>
</div>
)}
</>
);
}
export default Editform;
If I comment out the onClick for the button, the page renders. If it's in there, the page gets stuck in an infinite loop that even React doesn't catch.
The way I'm trying to recreate my array is based on advice I've read here, when searching, which said to take the original array, rebuild it item-for-item unless the ID matched the one I want to change, and to then write the new version in.
I suspect there might be a way to do it with my setter function (setCards), and I know there's an onChange available in React, but I don't know a) how to get it to work, or b) how - or even if I need to - pass the changed array back to the calling component.
Your function is invoked directly upon components render:
{saveChanges(thisCard)}
Rename it to a callback style signature:
{() => saveChanges(thisCard)}
Also do add a jsfiddle/ runnable snippet for answerers to test ✌️.
Edit:
About the array of objects passing and updates, at your part the code is good where filter is used. We can apply idea of moving update logic to parent where data is located.
Now id + updated attributes could be passed to the update callback in child.
To give you hint, can use spread operator syntax to update items out of existing objects.

Import images from object array in map with Webpack

I have an array of objects that looks like this:
export const NGOarray = [
{
name: "1% for the Planet ",
description:
"A leading global nonprofit, building a movement of businesses and individuals delivering philanthropic support to environmental organizations working on the front lines for our planet.",
link: "https://onepercentfortheplanet.org/",
category: ["water", "everything"],
logo: "1fortheplanet.webp",
},
{
name: "4ocean",
description:
"As both a public benefit corporation and Certified B Corp, we’re committed to ending the ocean plastic crisis.",
link: "https://www.4ocean.com",
category: ["water", "everything"],
logo: "4 Ocean.svg",
} ]
The logo property maps to the filename they have in a folder.
I'm trying to map through that array and show each image like this:
{NGOarray.map((org) => {
<div key={org.name}>
{org.logo && (
<img
src={
require(`../assets/organizations/${org.logo}`)
.default
}
/>
)}
<h3 className="text-2xl font-sans mb-4">{org.name}</h3>
<p>{org.description}</p>
</div>
);
}
But the image won't show up.
Any idea how I can get it to work?
Okay, this seems to have worked, leaving answer here for reference:
function importAll(r) {
return r.keys().map(r);
}
const logos = importAll(
require.context("../assets/organizations/", false, /\.(png|jpe?g|svg)$/)
);
And when mapping the array:
{NGOarray.map((org, index) => {
<div key={org.name}>
{org.logo && <img src={logos[index]} alt={org.name} />}
<h3 className="text-2xl font-sans mb-4">{org.name}</h3>
<p>{org.description}</p>
</div>
);
}

Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead. JS

When I am trying to render a component on my user's dashboard I get this error message:
Error: Objects are not valid as a React child (found: object with keys
{jobTitle, jobDescription, salaryRange, closingDate, onClick,
handleDelete}). If you meant to render a collection of children, use
an array instead.
I'm not sure why I'm getting it because I am mapping the variables.
Here is my code:
class MyJobOpenings extends Component {
state = {
jobOpenings: [],
};
componentDidMount = async () => {
const { data: jobOpenings } = await getJobOpenings();
this.setState({ jobOpenings });
};
handleClick = () => {
const application = document.querySelector(".active-application-grid");
const show = document.querySelector(".show-details");
const hide = document.querySelector(".hide-details");
application.classList.toggle("show-content");
show.classList.toggle("inactive");
hide.classList.toggle("inactive");
};
render() {
return (
<div>
<Helmet>
<title>Job Seeker | My Job Openings</title>
</Helmet>
<Sidenav />
<div className="my-applications-container">
<div className="my-applications-header">
<h1>My Job Openings</h1>
<Link to="/dashboard/my-job-openings/new">
<input type="submit" id="new-btn" value="New Job Opening" />
</Link>
</div>
<div className="my-applications">
{this.state.jobOpenings.map((jobOpening) => (
<ActiveJobOpening
key={jobOpening._id}
jobTitle={jobOpening.title}
jobDescription={jobOpening.description}
salaryRange={jobOpening.salary}
closingDate={jobOpening.closingDate}
onClick={this.handleClick}
handleDelete={this.handleDelete}
/>
))}
</div>
</div>
</div>
);
}
}
When I call the server with getJobOpenings(), this is the response I get from my server:
[{
"_id": "61e937fc8543d6ac4e5b8c7b",
"title": "Testing 123",
"description": "This is a job description for a web developer at jobseeker.com. If you would like to apply please email us at.",
"salary": "$20,000 - $49,999",
"closingDate": "2022-01-28T00:00:00.000Z",
"userId": "61e7fbcf04cfba5fd837c578",
"__v": 0
}, {
"_id": "61de9433b095d680fd8664be",
"title": "Web Developer",
"description": "This is a job description for a web developer. You will be required to produce and maintain a website for jobseeker.com. This description has to be between 100 and 2500 characters.",
"salary": "$0 - $19,999",
"closingDate": "2022-02-19T00:00:00.000Z",
"__v": 0
}]
ActiveJobOpening Component:
const ActiveJobOpening = (
jobTitle,
jobDescription,
closingDate,
salaryRange,
onClick,
handleDelete
) => {
return (
<div className="active-application-container">
<div className="active-application">
<div className="active-application-grid">
<p className="grid-item title">Job Title:</p>
<p className="grid-item content">{jobTitle}</p>
<p className="grid-item title">Job Description:</p>
<p className="grid-item content">{jobDescription}</p>
<p className="grid-item title">Salary Range:</p>
<p className="grid-item content">{salaryRange}</p>
<p className="grid-item title">Closing Date:</p>
<p className="grid-item content">{closingDate}</p>
</div>
<div className="show-details">
<input type="submit" value="Show More Details" onClick={onClick} />
</div>
<div className="hide-details inactive">
<input type="submit" value="Show Less Details" onClick={onClick} />
</div>
<div className="buttons">
<Link to="/dashboard/my-job-openings/:id">
<input type="submit" id="edit-btn" value="Edit" />
</Link>
<input
type="submit"
id="delete-btn"
value="Delete"
onClick={handleDelete}
/>
</div>
</div>
</div>
);
};
Can someone please help me figure out what's wrong?
You've passed all the props into the jobTitle variable.
const ActiveJobOpening = (
jobTitle, // <-- treated as the props object, rest are ignored
jobDescription,
closingDate,
salaryRange,
onClick,
handleDelete
) => { .... }
You should destructure these all from a single props object.
const ActiveJobOpening = ({
jobTitle,
jobDescription,
closingDate,
salaryRange,
onClick,
handleDelete
}) => { .... }
You have done this.state.jobOpenings.map and then sent _id, title, description etc to ActiveJobOpening component. And in the ActiveJobOpening component, you are taking them as parameters and trying to show them in the browser. But there is the problem. Your sending _id , title, description etc are object and object can't show in the browser. That's why "Objects are not valid as react child..." error is showing. You should take the key-value pairs as variables from the object and then return them. In that case, You can simply destructure the object and there will be declared variables of the keys. Return them and then browser will be able to show the value instead of trying to show an object and giving error.

Using keys to call an array for an item list. React.js

I would like to say that this is my first time using Stack Overflow and I apologize if I don't explain this well because I am not sure how to word it.
I am trying to make a resume with a worklist on my website. The thing is I have some that have one bullet point and others with multiple points. I want to call a prop that will allow me to update the array on Resume.js but declare generalize it so it will create a list, using the array for each individual item.
I declare:
let job = []
Because I get an error stating it is undefined, but I would like to use a prop or something like it to call it down to create different arrays for each time I call func. ResumeWorkItem.
function ResumeWorkItem(props)
{
{/*Trying to use JobList to create the array but I am not sure how to call it lower down.*/}
let job = []
const JobList = job.map((job, index) =>
<li key={index}>
{job.toString()}
</li>
);
return(
<>
<div className="res__work">
<div>
<h2 className='res__work__title'>
{props.title}
</h2>
</div>
<div>
<h3 className='res__work__jobtitle'>
{props.jobtitle}
</h3>
</div>
<div className='res__work__info'>
<ul>{JobList}</ul> {/*This is where I call JobList, but I want to set up job in Resume.js .*/}
</div>
</div>
</>
);
}
Here is where I want to call the array in file Resume.js:
<section className="res-work-exp">
<ResumeWorkItem
title = 'Title 1'
jobtitle = 'Job Title 1'
{/* This is where I want to call array 1*/}
/>
<ResumeWorkItem
title='Title 2'
jobtitle='Job Title 2'
{/* This is where I want to call array 2*/}
/>
I apologize if I didn't explain this well enough. I put a few comments to see if that will help get my point across.
I've made JobList into a function to take in list of items that could be mapped as you've suggested and then call it from ResumeWorkItem. You could also move ResumeWorkItem to App.js and import JobList if you want.
Consider the following sample:
App.js
import React from 'react';
import './style.css';
import { ResumeWorkItem } from './Resume.js';
export default function App() {
return (
<section className="res-work-exp">
<ResumeWorkItem
title="Title 1"
jobtitle="Job Title 1"
joblist={[1, 2, 3]}
/>
<ResumeWorkItem title="Title 2" jobtitle="Job Title 2" />
</section>
);
}
Resume.js
import React from 'react';
export const JobList = (jobs) =>
jobs.map((job, index) => <li key={index}>{job.toString()}</li>);
export function ResumeWorkItem(props) {
return (
<>
<div className="res__work">
<div>
<h2 className="res__work__title">{props.title}</h2>
</div>
<div>
<h3 className="res__work__jobtitle">{props.jobtitle}</h3>
</div>
<div className="res__work__info">
<ul>{props.joblist ? JobList(props.joblist) : ''}</ul>
</div>
</div>
</>
);
}

Categories

Resources