react function- infinite loop - Minified React error #301 - javascript

I want to initialize Cards by calling initializeInput. but it is getting called in loop and goes out of memory. But if i call same function on button click Reset it works fine.
How can i call initializeInput on start up ?
const CardsContainer = (props) => {
var inputNum1, inputNum2, inputNum3;
const [inputNumber, setInputNumber] = React.useState([inputNum1,inputNum2,inputNum3 ]);
const initializeInput = React.useCallback(() => {
inputNum1 = Math.floor(Math.random() * 10) + 1;
inputNum2 = Math.floor(Math.random() * 10) + 1;
inputNum3 = Math.floor(Math.random() * 10) + 1;
console.log("Inside initialize", inputNum1, inputNum2, inputNum3);
setInputNumber([inputNum1, inputNum2, inputNum3]);
}, [inputNum1, inputNum2, inputNum3]);
// *initializeInput(); --> if i include gives out of memory*
return (
<div class="Container">
<Cards inputNum={inputNumber[0]} />
<Cards inputNum={inputNumber[1]} />
<Cards inputNum={inputNumber[2]} />
<button onClick={initializeInput}>Reset </button>
</div>
);
};
ReactDOM.render(<CardsContainer />, document.querySelector("#root"));

Check useEffect hook to trigger something only the first time you mount a component.
Your problem here is you are calling initializeInput that is calling setInputNumber triggering a rerender and so on...

Related

My React code get crash some time but not always

I am building a project in which there is only a single question and it changes when pressing the refresh button. Everything is going well but sometimes the code crashes and the page gets blank (as shown in attached image) on pressing the refresh button.
import React from "react"
import questionsData from '../questionsData.js'
function Content(){
const [question, setQuestion] = React.useState({
heading:"",
hints : []
})
const [refresh, setRefresh] = React.useState(0)
React.useEffect(function(){
if(questionsData){
const randomNo = Math.floor(Math.random() * questionsData.length) + 1
let headinggg = questionsData[randomNo].heading
let hintsss = questionsData[randomNo].hints
setQuestion({
heading: headinggg,
hints: hintsss
})
}else{
document.write("loading")
}
},[refresh])
const sugg = question.hints.map((hint) => {
return(
<li>{hint}</li>
)
})
function renderQuestion(){
setRefresh(refresh + 1)
}
return(
<div className="content">
<div className="question">
<h4>{question.heading}</h4>
<br />
<span>You should say:</span>
<ul>
{sugg}
</ul>
</div>
<div className="action">
<div className="record">
<img src="images/211859_mic_icon.svg" alt="" />
</div>
<div className="refresh" onClick={renderQuestion}>
<img src="images/3994399_refresh_reload_repeat_rotate_sync_icon.svg" alt="" />
</div>
</div>
</div>
)
}
export default Content
You should remove the + 1 from the randomNo calculation, otherwise it could case an IndexOutOfBounds error:
const randomNo = Math.floor(Math.random() * questionsData.length);

React Native how to use removeEventListener

How can I replicate this code in React? I am new to react and I have not been able to get it, thank you very much in advance
<progress id="bar" value="0" max="110"></progress>
<button onclick="increment()" id="increment">one time</button>
<button onclick="unlimited()" id="multiple">multiple</button>
<script>
var puntaje = document.getElementById("bar").value;
document.getElementById("increment").addEventListener("click",increment)
function increment (e)
{ e.target.removeEventListener(e.type,increment);
document.getElementById("bar").value += 10;}
function unlimited (){document.getElementById("bar").value += 10}
</script>
Use state to determine if the button has already been clicked once:
const component = () => {
const [value, setValue] = React.useState(0);
const [hasIncrementedOnce, setHasIncrementedOnce] = React.useState(false);
const increment = () => setValue((current) => current + 10);
const incrementOnce = React.useCallback(() => {
if (!hasIncrementedOnce) {
increment();
setHasIncrementedOnce(true);
}
}, [hasIncrementedOnce])
return (
<>
<progress id="bar" value={value} max="110"></progress>
<button onClick={incrementOnce} id="increment" disabled={hasIncrementedOnce}>one time</button>
<button onClick={increment} id="multiple">multiple</button>
</>
);
}

How to conditionally reset state count with react hooks

After the user submits my form, the handleSubmit function runs and counts the number of li elements with class names containing "show" in my div showing all search results. It adds these counts all up with setStoreCount(prevCount => prevCount + 1) and I update my FAQ {searchCount} UI showing the number of search results with
useEffect(() => {
setSearchCount(storeCount) // collect all storeCount
}, [storeCount])
The problem: Say that the first search gets 5 results.
Then the UI would show FAQ 5. If you search the same thing again, you still get 5 results and would expect the UI to still show FAQ 5 but because the storeCount cannot reset to 0 it shows FAQ 10 (5 + 5) and then FAQ 15 (5 + 5 + 5) and so on.
Because my useEffect conditionally runs whenever storeCount changes, I cannot reset it to 0 because then I would always show FAQ 0.
How do I show the number of search results while refreshing the count on every search in the code below?
import React, { useState, useRef, useEffect } from 'react'
import ContentsWrap from '../../components/contents-wrap'
import FrequentList from './tabs/frequent'
import EstimateList from './tabs/estimate'
import ReturnList from './tabs/return'
import EtcList from './tabs/etc'
import SubsidiaryList from './tabs/subsidiary'
import ServiceList from './tabs/service'
import InList from './tabs/in'
import OutList from './tabs/out'
import styles from './index.module.scss'
export default function FAQ () {
const [tab, setTab] = useState('frequent')
const [storeText, setStoreText] = useState('') // stores searchbar text as user types
const [searchText, setSearchText] = useState('') // sends searchbar text to List component props on form submit
const [storeCount, setStoreCount] = useState(0) // stores count of each li element className that includes 'show'
const [searchCount, setSearchCount] = useState(0) // shows search count in UI
const searchContainer = useRef(null)
const handleSubmit = e => {
e.preventDefault()
setSearchText(storeText)
setTab('all')
setTimeout(() => {
// gets all <ul> children of <div class = "faq-list-wrap">
for (let i = 0; i < searchContainer.current.children.length; i++) {
// gets all <li> children of each <ul>
for (let j = 0; j < searchContainer.current.children[i].children.length; j++) {
// checks if each li class name has 'show'
if (searchContainer.current.children[i].children[j].className.includes('show')) {
console.log('count added')
setStoreCount(prevCount => prevCount + 1)
}
}
}
}, 100) // setTimeOut needed to target searchContainer after search and not before
}
const handleChange = newId => {
setTab(newId)
setStoreText('') // clear input value on tab click
setSearchText('') // show all search items on tab click
}
useEffect(() => {
setSearchCount(storeCount) // collect all storeCount
}, [storeCount])
return (
<ContentsWrap>
<div className="content-wrap content-width">
{/* <!-- S: faq-wrap --> */}
<div className="faq-wrap">
<div className="faq-title-wrap"><h2 className="title">FAQ {searchCount}</h2></div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Search"
className={styles.searchBox}
value={storeText}
onChange={e => {
setStoreText(e.target.value)
}}
/>
</form>
{/* <!-- S: faq-list-wrap --> */}
<div className="faq-list-wrap" ref={searchContainer} >
{tab === 'all' && (
<>
<FrequentList searchText={searchText} />
<EstimateList searchText={searchText} />
<ReturnList searchText={searchText} />
<EtcList searchText={searchText} />
<SubsidiaryList searchText={searchText} />
<ServiceList searchText={searchText} />
<InList searchText={searchText} />
<OutList searchText={searchText} />
</>
)}
{tab === 'frequent' && (
<FrequentList searchText={searchText}/>
)}
{tab === 'estimate' && (
<EstimateList searchText={searchText}/>
)}
{tab === 'return' && (
<ReturnList searchText={searchText} />
)}
{tab === 'subsidiary' && (
<SubsidiaryList searchText={searchText} />
)}
{tab === 'service' && (
<ServiceList searchText={searchText} />
)}
{tab === 'in' && (
<InList searchText={searchText} />
)}
{tab === 'out' && (
<OutList searchText={searchText} />
)}
{tab === 'etc' && (
<EtcList searchText={searchText} />
)}
</div>
{/* <!-- E: faq-list-wrap --> */}
</div>
{/* <!-- E: faq-wrap --> */}
</div>
</ContentsWrap>
)
}
The problem here is in your setStoreCount logic.
In this line in your for loop:
if (searchContainer.current.children[i].children[j].className.includes('show')) {
console.log('count added')
setStoreCount(prevCount => prevCount + 1)
}
It adds the 1 to the prevCount meaning if the prevCount is 5 (which is the number of results on the first search, it adds 1 to that and so on.
What you can do is reset the storeCount before you add the number of elements found. like so:
setTimeout(() => {
setStoreCount(0)
// gets all <ul> children of <div class = "faq-list-wrap">
for (let i = 0; i < searchContainer.current.children.length; i++) {
// gets all <li> children of each <ul>
for (let j = 0; j < searchContainer.current.children[i].children.length; j++) {
// checks if each li class name has 'show'
if (searchContainer.current.children[i].children[j].className.includes('show')) {
console.log('count added')
setStoreCount(prevCount => prevCount + 1)
}
}
}
}, 100) // setTimeOut needed to target searchContainer after search and not before
But this might make it like, it show FAQ 0 then the rest of the count after it loops. So I suggest count it first before you set the count, like so.
setTimeout(() => {
let count = 0
// gets all <ul> children of <div class = "faq-list-wrap">
for (let i = 0; i < searchContainer.current.children.length; i++) {
// gets all <li> children of each <ul>
for (let j = 0; j < searchContainer.current.children[i].children.length; j++) {
// checks if each li class name has 'show'
if (searchContainer.current.children[i].children[j].className.includes('show')) {
console.log('count added')
count++
}
}
}
setStoreCount(count)
}, 100) // setTimeOut needed to target searchContainer after search and not before
Your loop is just incrementing the storeCount perpetually. You should start a counter at zero at the start of the loop the loop and then assign the final value of the counter into your storeCount using setStoreCount.

Can't understand this behaviour

I have a simple notes app and delete isn't working properly, even though state is correctly updated.
The state is being updated correctly as I can see on the console.
But all the notes including and after that note that I click delete on are getting deleted on the DOM for some reason.
For example if I have 3 notes ["hello","hi","hey"], if I delete the second note("hi"), the state shows the correct notes ["hello","hey"] but both "hi" and "hey" are deleted on the page not just "hi" like it was supposed to.
I can't understand where I've gone wrong, so I'd like to correct it.
App.js:
handleDelete = (note_id) => {
const id = 'display-' + note_id;
console.log(id);
document.getElementById(id).style.display = 'none';//remove element
//delete the note and update state
const newNotesList = this.state.notesList;
newNotesList.splice(note_id,1);
this.setState({
notesList : newNotesList
})
console.log(this.state.notesList)
}
Display.js:
render(){
const notesList = this.props.notesList;
const displayNotes = notesList.map( (note,note_id) =>
<div id={ 'display-' + note_id } className="display">
{/*some code*/}
<button type="button" className="delete-button"
onClick = { () => this.props.handleDelete(note_id) } > Delete </button>
</div> );
return <div>{displayNotes}</div>;
}
do like this
// don't mutation object
// App.js
handleDelete = (note_id) => {
//delete the note and update state
const newNotesList = this.state.notesList.filter((item, index)=> index !== note_id)
this.setState({
notesList : newNotesList
})
}
// Display.js
render(){
const notesList = this.props.notesList;
const displayNotes = notesList.map( (note,note_id) =>
<div>
{/*some code*/}
<button type="button" className="delete-button"
onClick = { () => this.props.handleDelete(note_id) } > Delete </button>
</div> );
return <div>{displayNotes}</div>;
}
==== here is the reason ========
at first the state.note is ["hello","hi","hey"], in the function of handleDelete you delete "hi" and make the id of dispaly-1's display become to hidden, so when react render the state.note === ["hello","hey"] the element of "hey"'s id become dispaly-1 so "hey" will be hidden. you will only see "hello"
handleDelete = (note_id) => {
// this.state.notesList === ["hello","hi","hey"]
const id = 'display-' + note_id;
console.log(id);
// the problem is u hidden the next element
// 1. newNotesList.splice(note_id,1);
// 2. document.getElementById(id).style.display = 'none'
// two methods choose one or you will hidden two elements
document.getElementById(id).style.display = 'none';//remove element
//delete the note and update state
const newNotesList = this.state.notesList;
newNotesList.splice(note_id,1);
this.setState({
notesList : newNotesList
})
console.log(this.state.notesList)
// for example
// the `this.state.notesList` new is ["hello","hey"]
}
notesList.map( (note,note_id) =>
// `note` is ["hello","hey"] , u don't need hidden the `2rd` element
//you have been delete 'hi' ` the id of `display-1`'s display ==='hidden'
// now "hey"'s id is `display-1`
<div id={ 'display-' + note_id } className="display">
{/*some code*/}
<button type="button" className="delete-button"
onClick = { () => this.props.handleDelete(note_id) } > Delete </button>
</div> );
``

Fetch new page when user clicks a button using Svelte and Sapper

I am stuck at the part that fetch more data when user clicks a button on bottom of a page using Svelte and Sapper.
Here is the code.
<script context="module">
export function preload(page) {
return this.fetch(`https://reqres.in/api/users?page=${$count}`) // I know this is not goint to work. but when the button is clicked, I want to fetch page 2 and merge it with page 1 data, show data in ascending order(page1, page2)
.then(res1 => {
return res1.json()
}).then(res2 => {
return {
currentPage: res2.page,
per_page: res2.per_page,
notices: res2.data,
total: res2.total,
totalPage: res2.total_pages
}
})
}
</script>
<script>
import { count } from '../../store.js'; // export const count = writable(1); from store.js file
export let currentPage; // 1
export let per_page; // 6
export let notices;
export let total; // 12
export let totalPage; // 2
const handleClick= () => {
if ($count < totalPage) {
count.update(n => n + 1); // update count 1 to 2 and want to deliver changed value to fetch new page
}
}
</script>
<main>
<div id="container">
<h1 class="cont-tit">Notice Board</h1>
<div class="noti-list-wrap">
{#each notices as notice, i}
<ul class="noti-list">
<li>
<a rel=prefetch href={`notice/${notice.id}`}>
<p class="tit">{`${notice.first_name} ${notice.last_name}`}</p>
<hr />
<p class="date">
{`notice no.${i}`}
</p>
</a>
</li>
</ul>
{/each}
<div class="show-more" on:click={handleClick}>show me more</div>
</div>
</div>
</main>
At first I thought I could use $count to fetch page 2 data but import count store inside script context="module" won't work.
Is there a way to deliver changed value of store to function preload?
Don't try to load the extra data inside preload. Instead, treat that as the initial data — which it is — and append to it the normal way.
This is a simplified version — it doesn't worry about error handling, race conditions, or an initial page other than 1 — to give a general idea of what I mean:
<script context="module">
export async function preload(page) {
const res = await this.fetch('https://reqres.in/api/users?page=1');
const data = await res.json();
return {
currentPage: data.page,
per_page: data.per_page,
notices: data.data,
total: data.total,
totalPage: data.total_pages
};
}
</script>
<script>
export let currentPage;
export let per_page;
export let notices;
export let total;
export let totalPage;
const load_more = async () => {
currentPage += 1;
const res = await fetch('https://reqres.in/api/users?page=' + currentPage);
const data = await res.json();
notices = notices.concat(data.data);
};
</script>
<!-- other stuff -->
{#if currentPage < totalPage}
<button on:click={load_more}>show me more</button>
{/if}
I usually use the shortcut also to update the store value, like so:
const handleClick= () => {
if ($count < totalPage) {
$count = $count + 1); // update count 1 to 2 and want to deliver changed value to fetch new page
}
}
I don't see the code where you actually fetch the nth page base on count.

Categories

Resources