recently the project I am working on has been upgraded to React 18. By then, suddenly a lot of issues with hydration have started to appear as warnings/errors in the console. The one I'm struggling with is "Warning: Text content did not match":
Code of this component:
<div className="O75-product-faq__questions is-active accordion--initialized">
{
dataForSelect.length > 1 && <h4 className="O75-product-faq__questions__name js-category-name">{props.questionsByCategories[selectedCategory?.value].name}</h4>
}
{
props.questionsByCategories[selectedCategory?.value].questions.map((element, i) => (
<div key={i} className="O75-product-faq__questions__item">
{(element.question || props.showOnlyAnswer) && <div className={`O75-product-faq__questions__item__button${openedElement === i ? ' has-accordion-open' : ''}`} onClick={() => openElement(i)}>{element.question}</div>}
<AnimateHeight height={openedElement === i ? 'auto' : 0} duration={transitionDisabled ? 0 : 400}>
<div className="O75-product-faq__questions__item__content" dangerouslySetInnerHTML={{ __html: element.answer }} />
</AnimateHeight>
</div>))
}
</div>
I know that this issue results from the difference between client and server side rendering, but I don't know how to fix it and no other similar question contained solution that worked in my case.
Rest of the file, in case if the issue is not with aforementioned part:
import React, { useMemo, useState } from 'react';
import type { ReactElement } from 'react';
import AnimateHeight from 'react-animate-height';
import { BaseSelect, SelectOption } from '../molecules/base-select';
import type { FrequentlyAskedCategory } from './frequentlyAskedQuestion';
import { fromBase64 } from '../shared-services/base64Service';
interface FaqPanelProps {
mainTitle?: string;
menuTitle?: string;
showOnlyAnswer: boolean;
currentPageUrl: string;
questionsByCategories: Record<string, FrequentlyAskedCategory>,
faqStructuredDataBase64: string;
}
const FAQPanel = (props: FaqPanelProps): ReactElement => {
const categories = Object.keys(props.questionsByCategories);
const dataForSelect: Array<SelectOption> = categories.map(key => ({ label: props.questionsByCategories[key].name, value: key }));
const noOpenedElementIndex = -1;
const [openedElement, setOpenedElement] = useState<number>(-1);
const [selectedCategory, setSelectedCategory] = useState<SelectOption>(dataForSelect.length > 0 ? dataForSelect[0] : null);
const [transitionDisabled, setTransitionDisabled] = useState<boolean>(false);
const parsedStructuredData = useMemo(() => {
if(props.faqStructuredDataBase64 != null && props.faqStructuredDataBase64 !== ""){
return fromBase64(props.faqStructuredDataBase64);
}
return "";
}, [props.faqStructuredDataBase64]);
const selectNewCategory = (option: SelectOption): void => {
setTransitionDisabled(true);
setOpenedElement(noOpenedElementIndex);
setSelectedCategory(option);
}
const openElement = (index: number): void => {
if (transitionDisabled) {
setTransitionDisabled(false);
}
setOpenedElement(index === openedElement ? noOpenedElementIndex : index);
}
const speakableJson = JSON.stringify({
"#context": "https://schema.org/",
"#type": "WebPage",
"name": props.mainTitle,
"speakable":
[".O75-product-faq__headline",
".O75-product-faq__questions__item"],
"url": props.currentPageUrl
});
const hasFAQStructuredData = parsedStructuredData != null && parsedStructuredData !== "";
return (
<div className="container">
<section className="O75-product-faq" >
{
props.mainTitle
? <h2 className="O75-product-faq__headline">{props.mainTitle}</h2>
: <h4 className="O75-product-faq__categories-headline">{props.menuTitle}</h4>
}
<div className="flex">
{dataForSelect.length > 1 &&
<div className="O75-product-faq__categories">
<div className="filter__list is-hidden-sm filter">
{
dataForSelect.map((element, i) => (
<button className={`filter__btn js-filter__btn${element.value === selectedCategory?.value ? " is-active" : ""}`} key={i} onClick={() => selectNewCategory(element)}>
{element.label}
</button>))
}
</div>
<div className="filter__group is-hidden-md">
<BaseSelect selectedValue={selectedCategory}
handleChange={selectNewCategory}
options={dataForSelect} />
</div>
</div>
}
{categories.length > 0 &&
<div className="O75-product-faq__questions is-active accordion--initialized">
{
dataForSelect.length > 1 && <h4 className="O75-product-faq__questions__name js-category-name">{props.questionsByCategories[selectedCategory?.value].name}</h4>
}
{
props.questionsByCategories[selectedCategory?.value].questions.map((element, i) => (
<div key={i} className="O75-product-faq__questions__item">
{(element.question || props.showOnlyAnswer) && <div className={`O75-product-faq__questions__item__button${openedElement === i ? ' has-accordion-open' : ''}`} onClick={() => openElement(i)}>{element.question}</div>}
<AnimateHeight height={openedElement === i ? 'auto' : 0} duration={transitionDisabled ? 0 : 400}>
<div className="O75-product-faq__questions__item__content" dangerouslySetInnerHTML={{ __html: element.answer }} />
</AnimateHeight>
</div>))
}
</div>
}
</div>
{hasFAQStructuredData && <script suppressHydrationWarning type="application/ld+json" dangerouslySetInnerHTML={{__html:parsedStructuredData } }></script>}
<script suppressHydrationWarning type="application/ld+json" dangerouslySetInnerHTML={{__html: speakableJson}} ></script>
</section>
</div>
)
}
export { FAQPanel };
export type { FaqPanelProps }
Does anyone knows how to fix it?
Related
On my Localhost:3000, when I am running the code, I am getting an error saying:
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'id')
For the Source part, it is showing a certain section of my code, which is:-
;(async () => {
20 | setSelectedMarketNft(
> 21 | listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
| ^
22 | )
23 | })()
24 | }, [selectedNft, listings, isListed])
There are certain questions of the similar type on stackOverflow, but I am unable to find any answers from any of them. I am making a web3 project, where I am using next.js, sanity and thirweb.
The source code that contains this is:-
const MakeOffer = ({ isListed, selectedNft, listings, marketPlaceModule }) => {
const [selectedMarketNft, setSelectedMarketNft] = useState()
const [enableButton, setEnableButton] = useState(false)
useEffect(() => {
if (!listings || isListed === 'false') return
;(async () => {
setSelectedMarketNft(
listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
)
})()
}, [selectedNft, listings, isListed])
useEffect(() => {
if (!selectedMarketNft || !selectedNft) return
setEnableButton(true)
}, [selectedMarketNft, selectedNft])
Link to the full source code of the file where this error is occuring is:-
https://github.com/hemang-h/Standard-Demo-Marketplace-and-Minting/blob/main/components/nft/Purchase.js
Can anyone guide me what I am doing wrong here?
EXTRAS
Just for a better understanding, this is the full source code of the file where I am facing this error:
import { useEffect, useState } from 'react'
import { HiTag } from 'react-icons/hi'
import { IoMdWallet } from 'react-icons/io'
import toast, { Toaster } from 'react-hot-toast'
const style = {
button: `mr-8 flex items-center py-2 px-12 rounded-lg cursor-pointer`,
buttonIcon: `text-xl`,
buttonText: `ml-2 text-lg font-semibold`,
}
const MakeOffer = ({ isListed, selectedNft, listings, marketPlaceModule }) => {
const [selectedMarketNft, setSelectedMarketNft] = useState()
const [enableButton, setEnableButton] = useState(false)
useEffect(() => {
if (!listings || isListed === 'false') return
;(async () => {
setSelectedMarketNft(
listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
)
})()
}, [selectedNft, listings, isListed])
useEffect(() => {
if (!selectedMarketNft || !selectedNft) return
setEnableButton(true)
}, [selectedMarketNft, selectedNft])
const confirmPurchase = (toastHandler = toast) =>
toastHandler.success(`Purchase successful!`, {
style: {
background: '#04111d',
color: '#fff',
},
})
const buyItem = async (
listingId = selectedMarketNft.id,
quantityDesired = 1,
module = marketPlaceModule
) => {
console.log(listingId, quantityDesired, module, 'david')
// yo RAZA lets goooo!!!
//yo Qazi, ok
// sure okay about to run it...
// just clicked buy now...
// still error
// where can i see the contract address of the marketplace module
// in [nftId.js]
await module
.buyoutDirectListing({
listingId: listingId,
quantityDesired: quantityDesired,
})
.catch((error) => console.error(error))
confirmPurchase()
}
return (
<div className="flex h-20 w-full items-center rounded-lg border border-[#151c22] bg-[#303339] px-12">
<Toaster position="bottom-left" reverseOrder={false} />
{isListed === 'true' ? (
<>
<div
onClick={() => {
enableButton ? buyItem(selectedMarketNft.id, 1) : null
}}
className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}
>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>Buy Now</div>
</div>
<div
className={`${style.button} border border-[#151c22] bg-[#363840] hover:bg-[#4c505c]`}
>
<HiTag className={style.buttonIcon} />
<div className={style.buttonText}>Make Offer</div>
</div>
</>
) : (
<div className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>List Item</div>
</div>
)}
</div>
)
}
export default MakeOffer
selectedNFT is undefined as mentioned above.
The issue could be that it is running your code before it's defined.
This may go in your return function:
{(typeof selectedNFT != 'undefined') ? (
<div>Code that fetches from selectedNFT goes here.</div>
): (
<div>This could be a loading bar..</div>
)}
This will run your code ONLY after everything else executes.
You can check by console seletedNft inside makeoffer component to make sure you are getting props correctly and also check if its return object which has key with name "id" . Its cannot read id property in your selectedNft make sure its exist . I hope its help.
The error is solved, turns out that I just had to add
if(!selectedNft) return;
to successfully run my code. Final code will be as:
import { useEffect, useState } from 'react'
import { HiTag } from 'react-icons/hi'
import { IoMdWallet } from 'react-icons/io'
import toast, { Toaster } from 'react-hot-toast'
const style = {
button: `mr-8 flex items-center py-2 px-12 rounded-lg cursor-pointer`,
buttonIcon: `text-xl`,
buttonText: `ml-2 text-lg font-semibold`,
}
const MakeOffer = ({ isListed, selectedNft, listings, marketPlaceModule }) => {
const [selectedMarketNft, setSelectedMarketNft] = useState()
const [enableButton, setEnableButton] = useState(false)
useEffect(() => {
if(!selectedNft) return;
if (!listings || isListed === 'false') return
;(async () => {
setSelectedMarketNft(
listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
)
})()
}, [selectedNft, listings, isListed])
useEffect(() => {
if (!selectedMarketNft || !selectedNft) return
setEnableButton(true)
}, [selectedMarketNft, selectedNft])
const confirmPurchase = (toastHandler = toast) =>
toastHandler.success(`Purchase successful!`, {
style: {
background: '#04111d',
color: '#fff',
},
})
const buyItem = async (
listingId = selectedMarketNft.id,
quantityDesired = 1,
module = marketPlaceModule
) => {
console.log(listingId, quantityDesired, module, 'david')
// yo RAZA lets goooo!!!
//yo Qazi, ok
// sure okay about to run it...
// just clicked buy now...
// still error
// where can i see the contract address of the marketplace module
// in [nftId.js]
await module
.buyoutDirectListing({
listingId: listingId,
quantityDesired: quantityDesired,
})
.catch((error) => console.error(error))
confirmPurchase()
}
return (
<div className="flex h-20 w-full items-center rounded-lg border border-[#151c22] bg-[#303339] px-12">
<Toaster position="bottom-left" reverseOrder={false} />
{isListed === 'true' ? (
<>
<div
onClick={() => {
enableButton ? buyItem(selectedMarketNft.id, 1) : null
}}
className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}
>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>Buy Now</div>
</div>
<div
className={`${style.button} border border-[#151c22] bg-[#363840] hover:bg-[#4c505c]`}
>
<HiTag className={style.buttonIcon} />
<div className={style.buttonText}>Make Offer</div>
</div>
</>
) : (
<div className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>List Item</div>
</div>
)}
</div>
)
}
export default MakeOffer
It is main class where I am calling the child component (DeviceReplacementRequestsList.js). And child component's componentDidMount is not working. I don't know why this is happening. I saw some other answers but I think that were not related to my case.
Main Component.js
class DevicesTypes extends React.Component {
module_name = "Device Types";
create_function = "create_device_type";
get_function = "get_device_type";
render() {
return (
<WidgetGrid>
{
this.props.modules && this.props.modules[this.module_name] && this.props.modules[this.module_name].members && this.props.modules[this.module_name].members.find((x) => { return x.id == this.create_function }) ?
<article className="col-sm-5">
<NewDeviceType />
</article> : null
}
{
this.props.modules && this.props.modules[this.module_name] && this.props.modules[this.module_name].members && this.props.modules[this.module_name].members.find((x) => { return x.id == this.get_function }) ?
<article className="col-sm-7">
<DeviceTypeList permissions={this.props.modules && this.props.modules[this.module_name] && this.props.modules[this.module_name].members ? this.props.modules[this.module_name].members : []} />
</article> : null}
{
this.props.modules && this.props.modules[this.module_name] ?
<article className="col-sm-7">
<Text2Speech/>
</article> : null
}
{
this.props.modules && this.props.modules[this.module_name] ?
<article className="col-sm-5">
<NewDeviceReplacement/>
</article>: null
}
{
this.props.modules && this.props.modules[this.module_name] ?
<article className="col-sm-7">
<DeviceReplacementRequestsList/>
</article> : null
}
</WidgetGrid>
)
}
}
In last component DeviceReplacementRequestsList.js my componentDidMount is not triggering
DeviceReplacementRequestsList.js
export default class DeviceReplacementList extends React.Component {
constructor() {
super();
this.state = {
deviceData : [],
spinner : true
}
}
componentDidMount() {
console.log("hello")
this.getDeviceReplacementRequests();
}
getDeviceReplacementRequests() {
const queryPrams = "";
ds.getDeviceReplacementRequests(queryPrams,data => {
console.log(data);
this.setState({
deviceData : data
})
}, err => {
})
}
handleChanges(e) {
this.setState({
[e.target.name]: e.target.value
})
}
render() {
return (
<div>
<JarvisWidget editbutton={false} deletebutton={false} color="blueDark">
<header>
<span className="widget-icon"> <i className="fa fa-edit" /></span>
<h2>All Device Types</h2>
<button className="btn btn-trans float-right" type="button" onClick={this}>
<i className="fa fa-refresh"></i>
</button>
<div className="col-md-12">
<div className="loader"></div>
</div>
</header>
</JarvisWidget>
</div>
)}
Have you tried binding it first inside the constructor?
this.getDeviceReplacementRequests = this.getDeviceReplacementRequests.bind(this);
I have an already working site. I am working on updating a react template by adding a carousel or image slider at the bottom of the page. The idea is to display images from a folder using a mongodb collection. I created the carousel/slider component as follows:
import React, { Intl } from "react";
import Carousel from "react-multi-carousel";
const DeviceCarousel = ({ ImagesDevices }) => {
const responsive = {
superLargeDesktop: {
// the naming can be any, depends on you.
breakpoint: { max: 4000, min: 3000 },
items: 5,
},
desktop: {
breakpoint: { max: 2999, min: 1024 },
items: 3,
},
tablet: {
breakpoint: { max: 1023, min: 464 },
items: 2,
},
mobile: {
breakpoint: { max: 463, min: 0 },
items: 1,
},
};
return (
<div id='news'>
<div className='container'>
<h1>News & Articles</h1>
<Carousel responsive={responsive}>
{ImagesDevices.map((deviceimage) => {
const imagepath =`/images/gallery/${deviceimage.filename}`;
return (
<div className='carouselItem'>
<img src={imagepath} alt='Image' />
<div className='caption'>
<div className='caption-inner'>
<h4 className='no-bar'>{deviceimage.caption}</h4>
<h5 className='no-bar'>
{deviceimage.copyright}
</h5>
</div>
</div>
</div>
);
})}
</Carousel>
</div>
</div>
);
};
export default DeviceCarousel;
I then went on to call the component in my main template:
import Navbar from "../../components/Header";
import Footer from "../../components/Footer";
import ArticleInfo from "../../components/ArticleInfo";
import dynamic from 'next/dynamic';
import CompanyLink from "../../components/crossLinks/companyLink";
import ResearchGroupLink from "../../components/crossLinks/researchGroupLink";
import DeviceCarousel from "../../components/devices/DeviceCarousel";
const ImageLink = dynamic(() => import("../../components/crossLinks/imageLink"), {ssr: false});
const PublicationLink = dynamic(() => import("../../components/crossLinks/publicationLink"), {ssr: false});
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faBrain, faClock, faCheckCircle, faTimesCircle,
faHospitalUser, faAward, faBan, faUsers } from "#fortawesome/free-solid-svg-icons";
import Device from "../../models/Device";
import Company from "../../models/Company";
import ResearchGroup from "../../models/ResearchGroup";
import University from "../../models/University";
import Person from "../../models/Person";
import DeviceImageGallery from "../../models/DeviceImageGallery";
import dbConnect from "../../utils/dbConnect";
import Error from "next/error";
import axios from "axios";
import React, { useState, useEffect } from "react";
function getArticles(name) {
let nameArr = name.split(" ");
let queryString = "";
nameArr.forEach(function (item, index) {
queryString += item;
if (index !== nameArr.length - 1) {
queryString += "%20";
}
});
const URL = `xxxxxxxxxxxxxxxxxxxxxxx=${queryString}`;
return axios.get(URL, {
headers: { "Zotero-API-Version": "3" },
});
}
const DeviceTemplate = ({ errorCode, data,ImagesDevices}) => {
if (errorCode) {
return <Error statusCode={errorCode} />;
}
const deviceInfo = JSON.parse(data);
deviceInfo.researchGroupsId = JSON.parse(deviceInfo.researchGroupsId);
deviceInfo.commercialPartnersId = JSON.parse(deviceInfo.commercialPartnersId);
deviceInfo.authorId = JSON.parse(deviceInfo.authorId);
deviceInfo.verifiedId = JSON.parse(deviceInfo.verifiedId);
const [articles, setArticles] = useState([]);
useEffect(() => {
getArticles(name).then(function (result) {
setArticles(result.data);
});
}, []);
const {
name,
queryName,
researchGroupsId,
commercialPartnersId,
status,
implantLocation,
numImplantedToDate,
summary,
background,
videoLink,
clinicalTrials,
imageProcessorLocation,
elecNumber,
elecLayout,
elecDiameter,
elecPitch,
firstPatientYear,
fdaApprovalYear,
ceMarkYear,
endOfProductionYear,
lastUpdate,
authorId,
verifiedId
} = deviceInfo;
const imagePath = `/images/logos/devices/${queryName}.jpg`;
return (
<div>
<Navbar scrollEffect={true} />
<div id='device-profile'>
<div className='container'>
<div className='row mb-4'>
<div className='col-xs-3 col-sm-3 col-md-3'>
<ImageLink
id='device-logo'
className='border-image'
src={imagePath}
alternativeImage="/images/logos/devices/device.png"
/>
</div>
<div id='device-info' class='col-xs-9 col-sm-9 col-md-9'>
<h2>{name}</h2>
{ implantLocation && (
<p><FontAwesomeIcon icon={faBrain} size='1x' alt='implant location' />{implantLocation}</p>
)}
{ numImplantedToDate && (
<p><FontAwesomeIcon icon={faUsers} size='1x' alt='implant location' />{numImplantedToDate} implanted</p>
)}
{ status == "active" && (
<p><FontAwesomeIcon icon={faCheckCircle} size='1x' alt='active' />active</p>
)}
{ status == "inactive" && (
<p><FontAwesomeIcon icon={faTimesCircle} size='1x' alt='inactive' />inactive</p>
)}
</div>
</div>
{ summary && (
<div className='row mb-3'>
<p>{summary}</p>
</div>
)}
{ commercialPartnersId.length !== 0 && (
<div className='row mb-3'>
<h3>Commercial Partners {queryName} {ImagesDevices} </h3>
<ul className='cross-links d-flex flex-wrap p-1'>
{commercialPartnersId.map(partner => (
<CompanyLink
name={partner.name}
queryName={partner.queryName}
city={partner.city}
country={partner.country} />
))
}
</ul>
</div>
)}
{ researchGroupsId.length !== 0 && (
<div className='row mb-3'>
<h3>Academic Collaborators </h3>
<ul className='cross-links d-flex flex-wrap p-1'>
{researchGroupsId.map(partner => (
<ResearchGroupLink
name={partner.name}
queryName={partner.queryName}
university={partner.universityId && partner.universityId.name} />
))
}
</ul>
</div>
)}
{ (firstPatientYear || fdaApprovalYear || ceMarkYear || endOfProductionYear) && (
<div className='row mb-3'>
<h3>Milestones</h3>
<ul className='milestones'>
{ firstPatientYear && (
<li><FontAwesomeIcon icon={faHospitalUser} size='1x' alt='first patient'/>{firstPatientYear}: First patient implanted</li>
)}
{ ceMarkYear && (
<li><FontAwesomeIcon icon={faAward} size='1x' alt='CE mark approval'/>{ceMarkYear}: CE mark approval</li>
)}
{ fdaApprovalYear && (
<li><FontAwesomeIcon icon={faAward} size='1x' alt='FDA approval'/>{fdaApprovalYear}: FDA approval</li>
)}
{ endOfProductionYear && (
<li><FontAwesomeIcon icon={faBan} size='1x' alt='End of production'/>{endOfProductionYear}: End of production</li>
)}
</ul>
</div>
)}
{ (background || videoLink) && (
<div className='row mb-4'>
<h3>Background</h3>
<p dangerouslySetInnerHTML={{ __html: background }} />
<div dangerouslySetInnerHTML={{ __html: videoLink }} />
</div>
)}
{ (elecNumber || elecLayout || elecDiameter || elecPitch || imageProcessorLocation) && (
<div className='row mb-3'>
<h3>Device Specifications</h3>
<ul>
{ elecNumber && (
<li>Number of electrodes: {elecNumber}</li>
)}
{ elecLayout && (
<li>Electrode layout: {elecLayout}</li>
)}
{ elecDiameter && (
<li>Electrode diameter: {elecDiameter} μm</li>
)}
{ elecPitch && (
<li>Electrode pitch: {elecPitch} μm</li>
)}
{ imageProcessorLocation && (
<li>Image processor location: {imageProcessorLocation}</li>
)}
</ul>
</div>
)}
{ clinicalTrials.length !== 0 && (
<div className='row mb-3'>
<h3>Clinical Trials </h3>
<ul>
{ clinicalTrials.map(item => (
<li><a href={`xxxxxxxxxx/${item}`} target='_blank'>{item}</a></li>
))}
</ul>
</div>
)}
{articles.length !== 0 && (
<div className='row mb-3'>
<h3>Selected Publications </h3>
<ul className='cross-links'>
{articles.map(article => (
<PublicationLink
authors={article.data.creators}
title={article.data.title}
date={article.data.date}
journal={article.data.publicationTitle}
conference={article.data.proceedingsTitle}
doi={article.data.DOI}
issue={article.data.issue}
volume={article.data.volume}
pages={article.data.pages}
type={article.data.itemType} />
))
}
</ul>
</div>
)}
<div className='row mb-4'>
<ArticleInfo lastUpdate={lastUpdate} authorId={authorId} verifiedId={verifiedId}/>
<DeviceCarousel ImagesDevices={ImagesDevices}/>
</div>
</div>
</div>
<Footer />
</div>
);
};
export async function getServerSideProps({ query: { deviceName } }) {
dbConnect();
const deviceResult = await Device.findOne({
queryName: deviceName,
})
.populate({ path: "researchGroupsId", model: ResearchGroup,
select: "name university queryName",
populate: { path: "university", model: University, select: "name" }})
.populate({ path: "commercialPartnersId", model: Company,
select: "name queryName city country yearFounded yearDissolved" })
.populate({ path: "authorId", model: Person,
select: "firstName preferredName lastName queryName researchGroupId",
populate: { path: "researchGroupId", model: ResearchGroup, select: "universityId",
populate: { path: "universityId", model: University, select: "name" } } })
.populate({ path: "verifiedId", model: Person,
select: "firstName preferredName lastName queryName researchGroupId",
populate: { path: "researchGroupId", model: ResearchGroup, select: "universityId",
populate: { path: "universityId", model: University, select: "name" } } });
const thedevice=await Device.findOne({queryName:deviceName});
const iddevice=thedevice._id;
const errorCode = deviceResult ? false : 400;
deviceResult.researchGroupsId = JSON.stringify(deviceResult.researchGroupsId);
deviceResult.commercialPartnersId = JSON.stringify(deviceResult.commercialPartnersId);
deviceResult.authorId = JSON.stringify(deviceResult.authorId);
deviceResult.verifiedId = JSON.stringify(deviceResult.verifiedId);
deviceResult.lastUpdate = JSON.stringify(deviceResult.lastUpdate);
//the code that we changed is below
deviceResult._id=JSON.stringify(deviceResult._id);
const deviceImages = await DeviceImageGallery.find({deviceId:deviceResult._id}).sort({order:1});
//
return {
props: { errorCode: errorCode, data: JSON.stringify(deviceResult),ImagesDevices:JSON.stringify(deviceImages) },
};
}
export default DeviceTemplate;
ImagesDevices is an array that was arrived at in the async function below through querying of the mongodb collection, however when I call
<DeviceCarousel ImagesDevices={ImagesDevices}/>
as seen in the code I am given the error that the ImagesDevices.map in the slider component(the first set of code) is not a function. the ImagesDevices element that I arrived at from the second set of code when passed through the slider component seems to be giving this error.
I have read that this error happens when data is not in array format. I converted my ImagesDevices element into an array even though it already was. I am however still getting this error. everything was rendering fine until I made that call in my template. Any ideas on where my code is wrong? or am I calling my slider component wrong?
what's the logic or algorithm for a Carousel? I'm done my research for 1 item per display but in my case I need to display 3 items, when I click on the next I expect the first item is hidden and the 4th item appear.
<div className="App">
<div className="Container">
{items.map((item, i) => (
<div className={`item ${i < lastIndex ? "visible" : "hidden"}`}>
{item.name}
</div>
))}
</div>
<div className="prev">{"<"}</div>
<div className="next">{">"}</div>
</div>
https://codesandbox.io/s/frosty-babbage-djron?file=/src/App.js
You will have to keep track of the first and last index that should be displayed. Anything outside them, you can skip
import React, { useState } from "react";
import "./styles.css";
const items = [
{
name: "box 1"
},
{
name: "box 2"
},
{
name: "box 3"
},
{
name: "box 4"
},
{
name: "box 5"
}
];
export default function App() {
const [firstIndex, setFirstIndex] = useState(0);
const [lastIndex, setLastIndex] = useState(3);
return (
<div className="App">
{/* <h1>{lastIndex}</h1> */}
<div className="Container">
{items.map((item, i) => {
if (i >= firstIndex && i < lastIndex) {
return (
<div key={item.name} className={"visible"}>
{item.name}
</div>
);
} else {
return null;
}
})}
</div>
<div
className="prev"
onClick={() => {
if (firstIndex > 0) {
setFirstIndex(firstIndex - 1);
setLastIndex(lastIndex - 1);
}
}}
>
{"<"}
</div>
<div
className="next"
onClick={() => {
if (lastIndex < items.length) {
setFirstIndex(firstIndex + 1);
setLastIndex(lastIndex + 1);
}
}}
>
{">"}
</div>
</div>
);
}
https://codesandbox.io/s/elated-banach-6bfh2?file=/src/App.js
EDIT Updated the code to prevent first and last index going out of bound of items length
I hope this will help for you!
export default function App() {
const [startIndex, setStartIndex] = useState(1);
const [lastIndex, setLastIndex] = useState(3);
return (
<div className="App">
<div className="Container">
{
items.map((item, i) => {
if (i >= startIndex - 1 && i <= lastIndex)
return (
<div className={`item ${i < lastIndex ? "visible" : "hidden"}`} key={i}>
{item.name}
</div>
)
})
}
</div>
<div className="prev"
onClick={() => {
setStartIndex(startIndex - 1)
setLastIndex(lastIndex - 1)
}}
>{"<"}</div>
<div className="next"
onClick={() => {
setStartIndex(startIndex + 1)
setLastIndex(lastIndex + 1)
}}
>
{">"}
</div>
</div>
);
}
I want to render out messages and their replies in React (with TypeScript).
Messages are stored inside an array in the state and replies are stored inside a different array inside the state.
This is my current code, which results in not rendering out the message blocks:
public render(): React.ReactElement<ISpfxConversationsProps> {
const { channelTopics, topicReplies, errorMessage } = this.state;
const hideTitleContainer = this.props.isEditMode || this.props.title ? '' : styles.hidden;
const wpTitleClasses = `${styles.webpartHeader} ${hideTitleContainer}`;
return (
<div className={ styles.spfxTecanTeamsConversations }>
<div className={ styles.container }>
<div className={ wpTitleClasses }>
{ this.props.isEditMode && <textarea onChange={this.setTitle.bind(this)} className={styles["edit"]} placeholder={strings.WebpartTitlePlaceholder} aria-label={strings.WebpartTitlePlaceholder} defaultValue={this.props.title}></textarea> }
{ !this.props.isEditMode && <span className={styles["view"]}>{this.props.title}</span> }
</div>
{ errorMessage ? <p className={ styles.textError }>{errorMessage}</p> : null }
<div className={ styles.conversationsArea }>
{
channelTopics.map((topic: IChannelTopic, indexTopic) => {
return (
this.renderMessageBlock( topic.message, indexTopic),
topicReplies.filter(r => r.topicMessageId === topic.id).map((reply: ITopicReply, indexReply) => {
return (
this.renderMessageBlock(reply.message, indexReply, true)
)
})
)
})
}
</div>
</div>
</div>
);
}
public renderMessageBlock(message: IChannelMessage, index: Number, isReply: boolean = false) {
const replyStyle = isReply? '' : styles.messageReply;
const messageBlockClasses = `${styles.messageBlock} ${replyStyle}`;
return (
<div className={ messageBlockClasses} key={`teams-message-${message.id}-${index}`}>
<div className={ styles.messageHeader}>
<span className={ styles.messageAuthor }>
{ message.fromUserDisplayName ? message.fromUserDisplayName : strings.UnknownAccount }
</span>
<span className={ styles.messageDate }>
{ this.renderDate(message.createdDateTime) }
</span>
</div>
<div className={ styles.messageBody }>
{ message.deletedDateTime === null ? (message.contentType === 'html' ? renderHTML(message.content) : message.content) : this.renderDate(message.deletedDateTime) }
</div>
</div>
);
}
public renderDate(date: Date) {
return (
<div className={ styles.inlineBlock }>
<Moment format="d.M.yyyy">{date}</Moment> <Moment format="HH:mm:ss">{date}</Moment>
</div>
);
}
When I remove the 2nd .map() block + the comma right before, this one:
,
topicReplies.filter(r => r.topicMessageId === topic.id).map((reply: ITopicReply, indexReply) => {
return (
this.renderMessageBlock(reply.message, indexReply, true)
)
})
I get the first level messages, but I cannot get both to work. I haven't found yet a good example how this must be structured so that it works.
What do I need to change?
<div className={styles.conversationsArea}>
{/* The comma operator (,) evaluates each of its operands (from left to right) and returns the value of the last operand **/
channelTopics.map((topic: IChannelTopic, indexTopic) => {
return [
this.renderMessageBlock(topic.message, indexTopic),
topicReplies
.filter((r) => r.topicMessageId === topic.id)
.map((reply: ITopicReply, indexReply) => {
return this.renderMessageBlock(reply.message, indexReply, true);
})
]
})}
</div>