Too Many Re-Renders ReactJs - reactjs

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

Related

Separate queries into a different file

At the moment I have a react app that has multiple pages making different queries from Firebase and more specifically Firestore. These queries are at the top of the file with the code for the component in the return statement.
How do I separate the queries into a separate file so that the query can be called across multiple components without repeating the code for the query? I have a provided a sample page from my website, I would like to separate the query to get the createdBy property and put it into a function called getTicketCreatedBy for example that I can call.
I'm new to React so I'm just trying to understand how best to structure files in React.
Thanks
import React, { useState, useEffect, Fragment } from "react";
import { db } from "../../firebase";
import { updateDoc, doc, getDoc, onSnapshot } from "firebase/firestore";
import {
ArrowPathIcon,
CalendarIcon,
ExclamationCircleIcon,
Bars3Icon,
} from "#heroicons/react/24/outline";
import SelectFieldStandard from "../inputs/SelectFieldStandard";
export default function Details({ currentTicketData, currentTicketRef }) {
const updateTicketState = async () => {
await updateDoc(getUser, {
state: 5,
});
};
//Get CreatedBy property from the Users collection
const [createdByData, setCreatedByData] = useState("");
const createdByDocRef = doc(db, "Users", currentTicketData.createdBy);
useEffect(() => {
onSnapshot(createdByDocRef, (doc) => {
const newData = doc.data();
setCreatedByData(newData);
});
}, []);
return (
<div className="mt-5 md:col-span-1 md:mt-0">
<div className="shadow overflow-hidden rounded-md">
<div className="bg-white dark:bg-gray-800 px-4 py-5 sm:p-6">
<h1 className="mt-2 text-2xl font-bold leading-7 text-gray-900 dark:text-white sm:text-3xl sm:truncate">
Details
</h1>
<div className="pt-2">
<p className="text-sm font-medium text-gray-900 dark:text-white pt-2">
Created By
</p>
<p className="mt-2 flex items-center text-sm text-slate-700 dark:text-slate-400">
<Bars3Icon
className="flex-shrink-0 mr-1.5 h-5 w-5"
aria-hidden="true"
/>
{createdByData.firstName} {createdByData.lastName}
</p>
</div>
</div>
</div>
</div>
);
}
I can't seem to find any information online for how to separate Firebase queries.

How do I render component in this case ?My method is rendering infinite Components

function Design() {
const[designRows,setDesignRows]=useState([])
const design = useSelector((state) => state.design)
useEffect(()=>{
for (var i = 0; i < design; i++) {
setDesignRows([...designRows, <DesignRow key={i} />])
}
},[designRows])
return (
<>
<section className='mt-5 p-3 w-2/5'>
<div className=' text-center p-2 h-20 bg-gray-200 font-bold text-lg'>Game Design</div>
<div className='border p-3 mt-6 text-gray-500 font-medium text-sm'>
{designRows.map(data=>(
<>{data}</>
))}
</div>
</section>
</>
)
}
export default Design
above program is rendering infinite DesignRow components, I want to render "design" no of components.[design is my global/redux state]
The source of your problem is you are watching for designRows state and updating in the same useEffect, that is what is causing it to loop infinitely.
I don't understand exactly what you want to achieve, but I guess you want to render n number of components where n is the length of your design Array, if so you can try :
function Design() {
const [designRows, setDesignRows] = useState([])
const design = useSelector((state) => state.design)
return (
<>
<section className='mt-5 p-3 w-2/5'>
<div className=' text-center p-2 h-20 bg-gray-200 font-bold text-lg'>Game Design</div>
<div className='border p-3 mt-6 text-gray-500 font-medium text-sm'>
{design.length > 0 && design.map((d, key) => (<DesignRow key={key} />))}
</div>
</section>
</>
)
}
export default Design
Your code snippet will cause an infinite rendering of component because you are updating the value of designRows in useEffect and at the same time added it in the dependencies in useEffect. To fix this either remove the updating of designRows in useEffect or remove the designRows from dependency array in useEffect.
You need to change it to this:
useEffect(()=>{
for (var i = 0; i < design; i++) {
setDesignRows([...designRows, <DesignRow key={i} />])
}
},[design])
The second argument is the dependencies - when updated, it triggers the effect.

react js: infinite page rendering issue

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.

React - Prevent re-render whole list when delete element

I'm working on a toasts notifications system using React v17 and the React context API. I'm NOT using Redux.
The problem:
Toasts are dismissed automatically after a given delay. The toast element which is dismissed is removed from the list from the context. The problem is that each Toast component is re-render, the whole list is re-render, each time the list change.
I don't want that each component be re-rendered. Only the dismissed Toast component should be "re-render", understand deleted from the list displayed.
I put key attribute on my Toast components but it doesn't work as I expected it would.
Thank you for helping me !
The code below:
function Layout() {
const toastsContext = useContext(ToastsContext);
const toastsList = toastsContext.toastsList;
const [list, setList] = useState([]);
useEffect(() => {
setList(toastsList);
}, [toastsList]);
const displayToasts = list.map(toast =>
<Toast
key={toast.id.toString()}
id={toast.id}
color={toast.color}
title={toast.title}
message={toast.message}
dismissable={toast.dismissable}
showTime={toast.showTime}
autoDismissDelay={toast.autoDismissDelay}
redirectTo={toast.redirectTo} />
);
return(
<div className='bg-slate-800 text-slate-400 min-h-screen relative'>
<Header />
<Outlet />
<div className='fixed top-20 right-4 flex flex-col gap-2'>
{displayToasts}
</div>
</div>
);
}
export default Layout;
Toast component
import { memo, useCallback, useContext, useEffect, useState } from "react";
import { ToastsContext } from "../context/ToastsContext";
import { FiX, FiArrowRight } from 'react-icons/fi';
import { Link } from "react-router-dom";
function Toast({id, color, title, message, dismissable, autoDismissDelay, showTime, redirectTo}) {
const toastsContext = useContext(ToastsContext);
const [hiddenToast, setHiddenToast] = useState(false);
const getToastColor = () => {
switch (color) {
case 'primary':
return 'bg-sky-500';
case 'danger':
return 'bg-rose-500';
case 'success':
return 'bg-green-500';
default:
return 'bg-sky-500';
}
};
const dismissToast = useCallback(() => {
setHiddenToast(true);
setTimeout(() => {
document.getElementById(`toast${id}`).className = 'hidden';
toastsContext.dismissToast(id);
}, 310);
}, [id, toastsContext]);
useEffect(() => {
const interval = setInterval(() => {
dismissToast();
}, autoDismissDelay);
return () => {
clearInterval(interval);
}
}, [autoDismissDelay, dismissToast]);
return(
<div id={'toast'+id} className={`transition ease-out duration-300 text-slate-50 text-sm rounded-lg drop-shadow-lg opacity-100 ${getToastColor()} ${hiddenToast ? 'translate-x-20 opacity-0' : ''}`}>
<div className="w-72">
<div className={`${(redirectTo && redirectTo !== '') || (message && message !== '') ? 'py-2' : 'py-4'} px-4 flex font-semibold items-center`}>
<p>{title}</p>
<div className="ml-auto flex items-center">
{showTime ? <p className="text-xs mr-3">11m ago</p> : null}
{dismissable ?
<button type="button" className="flex items-center justify-center text-base" onClick={dismissToast}>
<FiX />
</button>
: null
}
</div>
</div>
{
redirectTo && redirectTo !== '' ?
<Link className={`border-t border-slate-700 bg-slate-800 rounded-b-lg px-4 py-3 font-medium hover:bg-slate-700 block`} to={redirectTo}>
<p className="flex items-center justify-between">
<span>{message ? message : 'See more'}</span>
<FiArrowRight />
</p>
</Link>
:
message ?
<div className={`border-t border-slate-700 bg-slate-800 rounded-b-lg px-4 py-3 font-medium`}>
<p className="flex items-center justify-between">
<span>{message}</span>
</p>
</div>
: null
}
</div>
</div>
);
};
export default memo(Toast);
That's the default behavior in react: When a component (eg, Layout) re renders, so to do all its children (the Toasts). If you want to skip rendering some of the toasts, then Toast will need to use React.memo. Also, for the memoization to work, the props to each Toast will need to stay the same from one render to the next. From looking at your code i think that will happen without any changes, but it's important to know so you don't think memo is enough on its own.
import { memo } from 'react';
function Toast() {
// ...
}
export default memo(Toast);

React:Can't perform a React state update on an unmounted component?

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 &&
<>
...
</>
}

Resources