So I have a page in react that is constantly rendering , say for eg. when I console log I can see that getting logged infinitely in a loop. is it some hook on some inner components that is getting rendered constantly I can't figure out
When i comment out
<CartContainer line_items = {line_items} />
it still doesnt solve the issue.
could useCartState() context be the issue?
Below is the page
import React, {useEffect} from "react"
import { CartContainer, NavigationBar } from "../components"
import {useRouter} from 'next/router'
import { useCartState } from "../context/Cart"
import { QuestionMarkCircleIcon } from '#heroicons/react/solid'
const getPaymentAPIStatus = async () =>
{
const response = await fetch("https://api.nowpayments.io/v1/status")
const data = await response.json()
}
const CartPage = () => {
const router = useRouter();
const {line_items, subtotal, total_items} = useCartState() // to get cart details --anaya
const isEmpty = line_items.length === 0
if(isEmpty)
return(
<div>
<NavigationBar/>
<p>Your cart is empty. Please add some items</p>
</div>
)
else {
return(
<div>
<NavigationBar/>
<div className="bg-white">
<div className="max-w-2xl mx-auto pt-16 pb-24 px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<h1 className="text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl">Shopping Cart</h1>
<form className="mt-12 lg:grid lg:grid-cols-12 lg:gap-x-12 lg:items-start xl:gap-x-16">
<section aria-labelledby="cart-heading" className="lg:col-span-7">
<h2 id="cart-heading" className="sr-only">
Items in your shopping cart
</h2>
<CartContainer line_items = {line_items} />
</section>
{/* Order summary */}
<section
aria-labelledby="summary-heading"
className="mt-16 bg-gray-50 rounded-lg px-4 py-6 sm:p-6 lg:p-8 lg:mt-0 lg:col-span-5"
>
<h2 id="summary-heading" className="text-lg font-medium text-gray-900">
Order summary
</h2>
<dl className="mt-6 space-y-4">
<div className="flex items-center justify-between">
<dt className="text-sm text-gray-600">Subtotal</dt>
<dd className="text-sm font-medium text-gray-900">{subtotal.formatted_with_symbol}</dd>
</div>
<div className="border-t border-gray-200 pt-4 flex items-center justify-between">
<dt className="flex items-center text-sm text-gray-600">
<span>Shipping estimate</span>
<a href="#" className="ml-2 flex-shrink-0 text-gray-400 hover:text-gray-500">
<span className="sr-only">Learn more about how shipping is calculated</span>
<QuestionMarkCircleIcon className="h-5 w-5" aria-hidden="true" />
</a>
</dt>
<dd className="text-sm font-medium text-gray-900">Free</dd>
</div>
<div className="border-t border-gray-200 pt-4 flex items-center justify-between">
<dt className="text-base font-medium text-gray-900">Order total</dt>
<dd className="text-base font-medium text-gray-900">{subtotal.formatted_with_symbol}</dd>
</div>
</dl>
<div className="mt-6">
<button
type="submit"
className="w-full bg-indigo-600 border border-transparent rounded-md shadow-sm py-3 px-4 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-50 focus:ring-indigo-500"
>
Checkout
</button>
</div>
<div className="mt-6 text-sm text-center">
<p>
or{' '}
<a href ={`${router.basePath}/ChooseProduct`} className="text-indigo-600 font-medium hover:text-indigo-500">
Continue Designing<span aria-hidden="true"> →</span>
</a>
</p>
</div>
</section>
</form>
</div>
</div>
</div>
)
}
}
export default CartPage
How do i solve this?
Thanks in advance!
Adding useCartState as requested
import {createContext, useEffect, useContext, useReducer} from 'react'
import {commerce} from '../../lib/commerce'
//need to correct this file to be a tsx file in the future
//Provides a context for Cart to be used in every page
const CartStateContext = createContext()
const CartDispatchContext = createContext()
const SET_CART = "SET_CART"
const initialState = {
total_items: 0,
total_unique_items: 0,
subtotal:[],
line_items: [{}]
}
const reducer = (state,action) => {
switch(action.type){
case SET_CART:
return { ...state, ...action.payload }
default:
throw new Error(`Unknown action: ${action.type}` )
}
}
export const CartProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const setCart = (payload) => dispatch({type: SET_CART, payload})
useEffect(() => {
getCart()
},[state]) // Getting the page to be rendered whenever the cart objects are changed
const getCart = async() => {
try {
const cart = await commerce.cart.retrieve()
setCart(cart)
} catch (error){
console.log("error")
}
}
return (
<CartDispatchContext.Provider value = {{setCart}}>
<CartStateContext.Provider value = {state}>
{children}
</CartStateContext.Provider>
</CartDispatchContext.Provider>
)
}
export const useCartState = () => useContext (CartStateContext)
export const useCartDispatch = () => useContext (CartDispatchContext)
The problem here is that you have a useEffect with state as a dependency, meaning that every time the state value is altered, the getCart function gets called.
Meanwhile, getCart sets the state within it.
Therefor, it creates a cycle where getCart sets the state, the useEffect callback runs as a result, getCart gets called again, sets the state again, and so on.
The bottom line is that you can not set the state inside of a function and call that function every time the state value is altered.
Related
In my application, I am making a request to the backend with redux-thunk and fetching the pricingData. I keep the items in the pricingData first 10 items in the items variable by passing certain operations. I want to update the questionRange variable with the first items[0] value. But using setQuestionRange immediately causes infinite loop.
So i tried these:
if i have an array with multiple elements, update the setQuestionRange. But but the error still persisted
React limits the number of renders to prevent an infinite loop.
if (items.length > 0) {
setQuestionRange(items[0])
}
I used useEffect. But this caused another error:
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
useEffect(() => {
if (items) {
setQuestionRange(items[0])
}
}, [items])
How can i solve this? Here is my component:
import { Container } from '#/components/Container'
import Filters from './Filters'
import Cost from './Filters/Cost'
import { useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getAllPricing } from '#/store/actions/pricingAction'
function SwirlyDoodle({ className }) {
return (
<svg
aria-hidden="true"
viewBox="0 0 281 40"
className={className}
preserveAspectRatio="none"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M240.172 22.994c-8.007 1.246-15.477 2.23-31.26 4.114-18.506 2.21-26.323 2.977-34.487 3.386-2.971.149-3.727.324-6.566 1.523-15.124 6.388-43.775 9.404-69.425 7.31-26.207-2.14-50.986-7.103-78-15.624C10.912 20.7.988 16.143.734 14.657c-.066-.381.043-.344 1.324.456 10.423 6.506 49.649 16.322 77.8 19.468 23.708 2.65 38.249 2.95 55.821 1.156 9.407-.962 24.451-3.773 25.101-4.692.074-.104.053-.155-.058-.135-1.062.195-13.863-.271-18.848-.687-16.681-1.389-28.722-4.345-38.142-9.364-15.294-8.15-7.298-19.232 14.802-20.514 16.095-.934 32.793 1.517 47.423 6.96 13.524 5.033 17.942 12.326 11.463 18.922l-.859.874.697-.006c2.681-.026 15.304-1.302 29.208-2.953 25.845-3.07 35.659-4.519 54.027-7.978 9.863-1.858 11.021-2.048 13.055-2.145a61.901 61.901 0 0 0 4.506-.417c1.891-.259 2.151-.267 1.543-.047-.402.145-2.33.913-4.285 1.707-4.635 1.882-5.202 2.07-8.736 2.903-3.414.805-19.773 3.797-26.404 4.829Zm40.321-9.93c.1-.066.231-.085.29-.041.059.043-.024.096-.183.119-.177.024-.219-.007-.107-.079ZM172.299 26.22c9.364-6.058 5.161-12.039-12.304-17.51-11.656-3.653-23.145-5.47-35.243-5.576-22.552-.198-33.577 7.462-21.321 14.814 12.012 7.205 32.994 10.557 61.531 9.831 4.563-.116 5.372-.288 7.337-1.559Z"
/>
</svg>
)
}
export function Pricing() {
const [fieldSelectionMultipliers, setFieldSelectionMultipliers] = useState(0)
const [questionRange, setQuestionRange] = useState(0)
const [audienceCount, setAudienceCount] = useState(100)
const [totalCost, setTotalCost] = useState(null)
const dispatch = useDispatch()
const { pricingData } = useSelector((state) => state.pricing.getPricingData)
const isPricingDataEmpty = Object.keys(pricingData).length === 0
const fieldsData =
!isPricingDataEmpty &&
pricingData.items.filter((item) => item.content_object.content_type === 27)
const comboboxData =
!isPricingDataEmpty &&
pricingData.items.filter((data) => data.content_object.content_type === 41)
let items = !comboboxData
? []
: comboboxData.map((item) => ({
id: item.content_object.nanoid,
name: item.content_object.name,
multiplier: item.multiplier,
}))
const selectedFields = JSON.parse(JSON.stringify(fieldsData))
const exchangeRate = !isPricingDataEmpty && +pricingData.exchange_rate
const basePrice = !isPricingDataEmpty && +pricingData.base_price
const calculateCost = () => {
let numberFormat = Intl.NumberFormat('en-US')
let rate = exchangeRate * basePrice
let questionRangeMultiplier = questionRange ? questionRange.multiplier : 0
let total_multiplier =
(+fieldSelectionMultipliers + +questionRangeMultiplier) * rate
let total = Math.round(total_multiplier * audienceCount * 100) / 100
setTotalCost(numberFormat.format(total))
}
useEffect(() => {
calculateCost()
}, [fieldSelectionMultipliers, questionRange, exchangeRate, audienceCount])
useEffect(() => {
dispatch(getAllPricing())
}, [])
// if (items) {
// setQuestionRange(items[0])
// }
// useEffect(() => {
// if (items) {
// setQuestionRange(items[0])
// }
// }, [items])
return (
<section
id="pricing"
aria-label="Pricing"
className="bg-slate-900 py-20 sm:py-32"
>
<Container>
<div className="bg-slate-900">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="text-center">
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
<span className="relative whitespace-nowrap">
<SwirlyDoodle className="absolute top-1/2 left-0 h-[1em] w-full fill-indigo-400" />
<span className="relative">Net fiyatlama,</span>
</span>{' '}
sometext
</h2>
<p className="my-5 text-lg text-slate-400">
sometext
</p>
</div>
</div>
<div className="relative">
<div className="absolute inset-0 h-1/2 bg-slate-900" />
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="mx-auto max-w-lg overflow-hidden rounded-lg shadow-lg lg:flex lg:max-w-none">
<div className="flex-1 bg-white px-6 py-8 lg:p-12">
<h3 className="text-2xl font-bold text-gray-900 sm:text-3xl sm:tracking-tight">
sometext
</h3>
<div className="mt-8">
<div className="flex items-center">
<h4 className="flex-shrink-0 bg-white pr-4 text-base font-semibold text-indigo-600">
sometext
</h4>
<div className="flex-1 border-t-2 border-gray-200" />
</div>
{selectedFields && (
<Filters
selectedFields={selectedFields}
fieldSelectionMultipliers={fieldSelectionMultipliers}
setFieldSelectionMultipliers={
setFieldSelectionMultipliers
}
/>
)}
</div>
</div>
{comboboxData && (
<Cost
items={items}
questionRange={questionRange}
setQuestionRange={setQuestionRange}
audienceCount={audienceCount}
setAudienceCount={setAudienceCount}
totalCost={totalCost}
/>
)}
</div>
</div>
</div>
</div>
</Container>
</section>
)
}
I've implemented a lazy loading hook, but for some reason the carousel component is not loading at all. I've got it from here: https://betterprogramming.pub/lazy-loading-in-next-js-simplified-435681afb18a
This is my child that I want to render when it's in view:
import { useRef } from "react";
import Carousel from "../components/carousel";
import useOnScreen from "../hooks/useOnScreen";
// home page
function HomePage() {
const carouselRef = useRef();
const carouselRefValue = useOnScreen(carouselRef);
return (
<div className="snap-y">
{/* 1 */}
<div className="flex justify-center items-start relative min-h-[calc(100vh_-_5rem)] bg-black snap-start ">
{/* Cone */}
<div className="absolute w-full max-w-full overflow-hidden min-w-fit cone animate-wiggle"></div>
<div className="grid justify-center grid-cols-4 max-w-7xl">
//Content
</div>
{/* 2 */}
<div className="z-20 pb-4 bg-black snap-start" ref={carouselRef.current}>
{carouselRefValue && <Carousel />}
</div>
{/* 3 */}
<div className="flex items-start justify-center py-32 min-h-fit bg-slate-50 snap-start">
//More content
</div>
);
}
export default HomePage;
useOnScreen hook:
import { useState, useEffect } from "react";
const useOnScreen = (ref: any) => {
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => setIntersecting(entry.isIntersecting));
if (ref.current) {
observer.observe(ref.current);
}
}, []);
return isIntersecting;
};
export default useOnScreen;
Edit: Needed to add const carouselRef = useRef() as React.MutableRefObject<HTMLInputElement>; paired with #asynts's answer.
This is incorrect:
<div className="z-20 pb-4 bg-black snap-start" ref={carouselRef.current}></div>
it should be:
<div className="z-20 pb-4 bg-black snap-start" ref={carouselRef}></div>
I have auto scroll function and scroll will start when user click the function as follow.
It is scroll 50px to y axis once when user click play button. But it is only scroll once even thought I have added interval. Interval is working because I saw the "scrolling" console.log is increasing. But scroll is not scrolling again.
May I know why scroll is not move again?
import React, { useState, useEffect, useRef } from "react";
import { useParams, NavLink } from "react-router-dom";
import { useQuery } from "#apollo/client";
import { getTrack, getTrackVariable } from "../../gql/track";
import ChordSheetJS from "chordsheetjs";
import {
YoutubeIcon,
FacebookIcon,
PlayIcon,
PauseIcon,
} from "../../assets/icons/svg_icons";
import { SettingIcon } from "../../assets/icons/svg_icons";
import paths from "../../routes/paths";
import { FacebookShareButton } from "react-share";
import GoTop from "../../components/go_top";
const TrackPage = () => {
const intervalId = useRef(null);
const { trackId } = useParams();
const [track, setTrack] = useState();
const [collapse, setCollapse] = useState(true);
const [play, setPlay] = useState(false);
const [speed, setSpeed] = useState(1);
const { loading, error, data } = useQuery(getTrack, {
variables: getTrackVariable(trackId),
});
const trackRef = useRef();
useEffect(() => {
if (!loading && !error) {
setTrack(data?.track);
}
}, [loading, error, data]);
const getChordSheet = (value) => {
const parser = new ChordSheetJS.ChordProParser();
const song = parser.parse(value);
const formatter = new ChordSheetJS.HtmlTableFormatter();
const chordSheet = formatter.format(song);
return chordSheet;
};
const handleError = (e) => {
e.target.onerror = null;
e.target.src = Monk;
};
const handleMenuCollapse = (e) => {
e.preventDefault();
setCollapse(!collapse);
};
const handleSpeedUp = () => {
setSpeed(speed + 1);
};
const handleSpeedDown = () => {
setSpeed(speed - 1);
};
const handleScroll = () => {
setPlay(!play);
if (play) {
console.log("stop");
clearInterval(intervalId.current);
} else {
let delayInMs = 100;
const onScrollStep = () => {
document.getElementById("content").scroll(0,50);
console.log("srolling")
};
intervalId.current = setInterval(onScrollStep, delayInMs);
console.log("play");
}
};
return (
<>
<div id="setting">
{/** the big div */}
<div
className={` w-36 h-56 bg-primary absolute top-[calc((100vh-384px)/2)] ${
collapse ? "hidden" : "right-0"
} " bg-primary rounded-b-lg items-center justify-center`}
>
<div>
<div className="items-center justify-center mt-5">
<div className="flex text-xs items-center justify-center ">
<span className=" text-sm text-white">Scroll</span>
</div>
<div className="flex text-xs pt-0 mt-0 items-center justify-center ">
<button
className="px-2 btn-sm flex w-20 items-center bg-transparent hover:bg-accent border text-white font-semibold hover:text-white border-white hover:border-transparent rounded "
onClick={handleScroll}
>
{play ? (
<PauseIcon className="text-white mr-2" />
) : (
<PlayIcon className="text-white mr-2" />
)}
{play ? <span>Pause</span> : <span>Play</span>}
</button>
</div>
<div className="flex text-xs items-center justify-center mt-2">
<button
className="w-auto bg-transparent mr-2 hover:bg-accent text-white font-semibold hover:text-white py-1 px-2 border border-white hover:border-transparent rounded"
onClick={handleSpeedDown}
>
-1
</button>
<button
className="w-auto bg-transparent ml-2 hover:bg-accent text-white font-semibold hover:text-white py-1 px-2 border border-white hover:border-transparent rounded"
onClick={handleSpeedUp}
>
+1
</button>
</div>
</div>
</div>
</div>
{/** the icon div */}
<div
className={`flex w-12 absolute top-[calc((100vh-384px)/2)] h-12 bg-primary
${collapse ? "animate-pulse right-0" : "right-36"}
cursor-pointer bg-primary rounded-l-lg items-center justify-center`}
onClick={handleMenuCollapse}
>
{/* <div className="w-5 h-5 bg-white rounded-full " /> */}
<SettingIcon />
</div>
</div>
<div id="track" ref={trackRef}>
<div className="flex flex-col w-full py-1 my-1 items-center bg-gray-50">
<div className="relative my-6 mx-auto md:min-w-[60%] max-h-full">
{track ? (
<div className="w-full">
<pre
className="px-5 textarea"
dangerouslySetInnerHTML={{
__html: getChordSheet(track.lyric),
}}
/>
</div>
) : (
<div></div>
)}
</div>
</div>
</div>
</>
);
};
export default TrackPage;
app.jsx
import React, { useState, useEffect } from "react";
import Header from "./components/header";
import SideMenu from "./components/side_menu";
import AppRoutes from "./routes";
import withUser from "./hocs/with_user";
import { isMobile } from "react-device-detect";
import { useLocation } from "react-router-dom";
import { AuthProvider, setAccessToken } from "./auth/auth_provider";
import { Toaster } from "react-hot-toast";
import AppContext from "./components/app_context";
import "./i18n";
import "./App.css";
function App(props) {
const [collapse, setCollapse] = useState(isMobile);
const [sideBarFull] = useState(true);
const location = useLocation();
const IsNormalPage = () => {
const blankPages = ["/login"];
for (let i = 0; i < blankPages.length; i++) {
if (location.pathname.startsWith(blankPages[i])) return
false;
}
return true;
};
useEffect(() => {
if (props.user) setAccessToken(props.user.t);
}, []);
const PageHeader = () => {
return (
<div className="h-[72px] w-full flex items-center align-middle justify-center bg-neutral shadow">
<div className="w-full text-center">
<Header />
</div>
</div>
);
};
return (
<AuthProvider user={props.user}>
<AppContext.Provider
value={{
collapse: collapse,
setCollapse: setCollapse,
}}
>
<div className="relative w-full min-h-screen h-full">
<div className="flex flex-row min-h-screen">
<div className="w-auto z-0 ">
<div className="flex-1 w-full max-h-screen mx-auto text-lg h-full shadow-lg bg-white overflow-y-auto">
{IsNormalPage() && <SideMenu showFullMenu={sideBarFull} />}
</div>
</div>
<div className="w-full max-h-screen flex flex-col z-10">
{IsNormalPage() && <PageHeader />}
<div id="content" className="flex-1 w-full max-h-screen mx-auto text-lg h-full shadow-lg bg-white overflow-y-auto">
<Toaster />
<AppRoutes />
</div>
</div>
</div>
</div>
</AppContext.Provider>
</AuthProvider>
);
}
export default withUser(App);
I think because you are toggling the play state in your component
setPlay(!play);
Are you trying to scroll to a specific div or just scroll for 50 px in the direction of y-axis? there are two approaches, you can use window or Refs.
an example using the refs to scroll to a specific node in the dom
const ScrollDemo = () => {
const myRef = useRef(null)
const executeScroll = () => { myRef.current.scrollIntoView()}
return (
<div>
<div ref={myRef}>Element to scroll to</div>
<button onClick={executeScroll}> Click to scroll </button>
<div/>
)
}
or if you just want to just scroll 50 pixel in the direction of y-axis
const scrollToTop = () => {
window.scrollTo(0,50);
};
return (
<button onClick={scrollToTop}>
Go down 50 px!
</button>
);
window.scrollTo is only working with html body. document.getElementById is only working overflow div.
useEffect(() => {
if (play) {
const onScrollStep = () => {
var e = document.getElementById("content");
if (e.scrollHeight - e.scrollTop === e.clientHeight) {
clearInterval(intervalId.current);
setPlay(!play);
return;
}
e.scroll(0, e.scrollTop + speed);
};
intervalId.current = setInterval(onScrollStep, delayInMs);
} else {
clearInterval(intervalId.current);
}
},[play, speed])
Can someone please help me why this code showing me " Can't perform a React state update on an unmounted component" error while refreshing the page?
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
const [loading, setLoading] = useState(true);
const [course, setCourse] = useState({});
const router = useRouter();
const { slug } = router.query;
//fetch course from backed using slug
useEffect(() => {
setLoading(true);
loadSingleCourse();
}, [slug]);
const loadSingleCourse = async () => {
const { data } = await axios.get(`/api/course/${slug}`);
setCourse(data);
setLoading(false);
// console.log(data);
};
I can access course state but Even after having loading state its throwing me error of state update on unmounted component. This is my render :
{loading ? (
"Loading.."
) : (
<>
<div className="max-w-2xl px-6 py-16 mx-auto space-y-12">
<article className="space-y-8 ">
{/* <div>
<img
className="w-full h-72 rounded-xl shadow-xl"
src={course.image.Location}
/>
</div> */}
<div className="space-y-6">
<h1 className="text-4xl font-bold md:tracking-tight md:text-5xl text-accent">
{course.title}
</h1>
<div className="flex flex-col items-start justify-between w-full md:flex-row md:items-center dark:text-coolGray-400">
<div className="flex items-center md:space-x-2">
<img
src="https://source.unsplash.com/75x75/?portrait"
alt=""
className="w-4 h-4 border rounded-full dark:bg-coolGray-500 dark:border-coolGray-700"
/>
<p className="text-sm">
{course.instructor.name} • {course.createdAt}
</p>
</div>
</div>
</div>
<div className="dark:text-coolGray-500">
<p>{course.description}</p>
</div>
</article>
<div>
<div className="flex flex-wrap py-6 space-x-2 border-t border-dashed dark:border-coolGray-400">
<p className="px-3 py-1 rounded-md hover:underline bg-primary text-accent">
#{course.category}
</p>
<p className="px-3 py-1 rounded-md hover:underline bg-accent text-primary">
{course.lessons.length} Lessons
</p>
{/* Add Lession Modal */}
<div>
<label
for="add-lesson-modal"
className="border-2 flex align-center items-center text-accent py-1 rounded-md px-2 cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-11a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V7z"
clip-rule="evenodd"
/>
</svg>
Add Lesson
</label>
<input
type="checkbox"
id="add-lesson-modal"
className="modal-toggle"
/>
<div className="modal">
<div className="modal-box overflow-scroll">
<AddLessonForm
handleAdd={handleAddLesson}
values={values}
setValues={setValues}
uploading={uploading}
course={course}
uploadVideoText={uploadVideoText}
handleLessonVideo={handleLessonVideo}
uploadProgress={uploadProgress}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)}
When I try to refresh its showing me:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
Error image of render
Your code is missing something - the function and the export. I have also included an alternate way to render if loading is true:
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
const SomeComponent = () => {
const [loading, setLoading] = useState(true);
const [course, setCourse] = useState({});
const router = useRouter();
const { slug } = router.query;
//fetch course from backed using slug
useEffect(() => {
setLoading(true);
loadSingleCourse();
}, [slug]);
const loadSingleCourse = async () => {
const {data} = await axios.get(`/api/course/${slug}`);
setCourse(data);
setLoading(false);
// console.log(data);
};
if (loading) {
return (
<>Loading...</>
);
}
return (
<>
...
</>
);
}
export default SomeComponent;
This syntax worked for me didn't know why loading state was not working!
I have also tried with some cleanup but nothing worked.
{course &&
<>
...
</>
}
Well Im Trying To Basically Use Speech To Text With React-Speech-Recognition Package, I Tried To Make a Button Icon Which Stops onClick When The Mic Was Off or Turns on When Earlier it Was off
I Tried a Lot To Fix the Issue,
here's My Code.
import React, { Component, useRef } from "react";
import firebase from "../firebase";
import { createSpeechlySpeechRecognition } from "#speechly/speech-recognition-polyfill";
import SpeechRecognition, {
useSpeechRecognition,
} from "react-speech-recognition";
var axios = require("axios").default;
export default function Chat() {
let messages = [{ main: "Hey there! Wassop", class: "left" }];
let messageRef = useRef();
const appId = "I_HAVE_MY_KEY_HERE";
const SpeechlySpeechRecognition = createSpeechlySpeechRecognition(appId);
SpeechRecognition.applyPolyfill(SpeechlySpeechRecognition);
const {
transcript,
listening,
browserSupportsSpeechRecognition,
isMicrophoneAvailable,
} = useSpeechRecognition();
const startListening = () =>
SpeechRecognition.startListening({ continuous: true });
function Mic() {
if (listening) {
return SpeechRecognition.stopListening()
} else {
return SpeechRecognition.abortListening()
}
}
function onSend(e) {
let message = messageRef.current.value;
e.preventDefault();
document.getElementById("messages").innerHTML +=
"<div class='right'>" + message + "</div>";
if (message == "") {
alert("Field shall not be empty!");
}
var options = {
---API REQUEST----
};
axios
.request(options)
.then(function (response) {
messageRef.current.value = "";
messages.push({
main: response.data.cnt,
class: "left",
});
document.getElementById("messages").innerHTML +=
"<div class='left'>" + response.data.cnt + "</div>";
console.log(messages);
})
.catch(function (error) {
console.error(error);
});
}
return (
<div className="card">
<h1 className="text-2xl text-center font-bold">Chat Box</h1>
<p>Microphone: {listening ? "on" : "off"}</p>
<p>{transcript}</p>
<br />
<div id="messages">
{messages.map((message) => (
<div key={message.main} className={message.class}>
{message.main}
</div>
))}
</div>
<br />
<form onSubmit={onSend}>
<div class="relative flex w-2/4 flex-wrap items-stretch mb-3">
<span class="z-10 h-full leading-snug font-normal absolute text-center text-blueGray-300 absolute bg-transparent rounded text-base items-center justify-center w-8 pl-3 py-3">
<img src="https://img.icons8.com/external-flatart-icons-flat-flatarticons/64/000000/external-message-contact-flatart-icons-flat-flatarticons.png" />
</span>
<input
type="text"
ref={messageRef}
placeholder="Message"
class="px-3 py-3 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-sm border-0 shadow outline-none focus:outline-none focus:ring w-full pl-10"
/>
<span class="z-10 h-full leading-snug font-normal absolute text-center text-blueGray-300 absolute bg-transparent rounded text-base items-center justify-center w-8 right-0 pr-3 py-3 mic">
<img
src="https://img.icons8.com/material-rounded/24/000000/microphone.png"
onClick={Mic()}
/>
</span>
</div>
<button
type="submit"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Button
</button>
</form>
</div>
);
}
I Get The Error Of Too Many Renders Which Im Not Able To Figure Out How To Fix I Tried Loooking a lot But Nothing Helped, Im Not Even Able To Understand Someone Please Help Me.
Reason for too much re-render
If you are binding your onClick functions like this:
onClick={Mic()}
React will call the function, without the need of an actual click. You should use onClick={Mic} or onClick={() => Mic()}
There are a couple of other issues with your code:
1. Using ref
You are using a useRef variable to hold the messageuseRef update will not trigger a re-render. Instead try to use a useState hook to bind the variable to a state variable
2. Creating the object inside the functional component
You are creating messages object inside the functional component. On every re-render, this messages object will be initialized to the same array. Bind this to a state variable to reflect changes made to the messages object.
import {useState} from 'react'
const [messages, setMessages] = useState([{ main: "Hey there! Wassop", class: "left" }])
3. DOM Manipulation
You should avoid DOM manipulation like:
document.getElementById("messages").innerHTML += "<div class='right'>" + message + "</div>";
if possible. You can use refs in this case and bind it to the JSX.
const messageRef = useRef('')
return(
...
<div id="message" ref={messageRef}> ...
...
)
I will strongly suggest reading more about React lifecycle and hooks:
Docs