State not showing updated value in console - javascript

Although the text gets updated on the page, the console.log still logs out the initial value. Why is this? I know that setting the state is asynchronous but why does it still log out the old value even after waiting 1 second?
import { useState, useEffect, useRef } from "react";
function App() {
const [requestState, setRequestState] = useState("initial");
useEffect(() => {
setRequestState("changed");
setTimeout(() => {
console.log(requestState);
}, 1000);
}, []);
return (
<div className="App">
{requestState}
</div>
);
}
export default App;

useEffect will run when the component renders,To call a function conditionally, specify the list of dependencies.
And the rule of thumb is to always add those dependencies that you are using inside the useEffect()
import { useState, useEffect, useRef } from "react";
function App() {
const [requestState, setRequestState] = useState("initial");
setRequestState("changed");
useEffect(() => {
setTimeout(() => {
console.log(requestState);
}, 1000);
}, [requestState]);
return (
<div className="App">
{requestState}
</div>
);
}
export default App;

The useEffect() hook "captures" state and props when it is executed. That is why it has a stale value. The value is from when the function in useEffect() was run.
This is a beautiful article by Dan Abramov: https://overreacted.io/a-complete-guide-to-useeffect/. It has an explanation about almost the exact same problem as yours. Read it completely to have a great insight into useEffect()

Your useEffect depends on the requestState varible, so pass it inside the empty list like so:
useEffect(() => {some code},[used variables])

Related

React component re-rendering many times

i have a react component thats keep re-rendering idk why but i think the reason is the data fetching
data code :
export function KPI_Stock_Utilisation() {
const [kpi_stock_utilisation, setKpi_stock_utilisation] = useState([{}]);
useEffect(() => {
axios.get("http://localhost:5137/KPI_Stock_Utilisation").then((response) => {
setKpi_stock_utilisation((existingData) => {
return response.data;
});
});
}, []);
console.log('data get')
return kpi_stock_utilisation;
}
this log displayed many times , and the log in the component too
component code :
import React from "react";
import { KPI_Stock_Utilisation } from "../../Data/data";
import { useEffect } from "react";
export default function WarehouseUtilisChart(props) {
let kpi_stock_utilisations =KPI_Stock_Utilisation();
let Stock_utilisation = (kpi_stock_utilisations.length / 402) * 100;
console.log('component render')
return (
<div>
<p>{kpi_stock_utilisations}</p>
</div>
);
}
im new with react i tried useEffect inside the componenets but its not working
Calling the react custom hook KPI_Stock_Utilisation several times will for sure render more than once.
in your case I suggest you use useEffect in the same component as I will show you.
import React,{useEffect,useRef} from "react";
import { KPI_Stock_Utilisation } from "../../Data/data";
import axios from 'axios';
export default function WarehouseUtilisChart(props) {
const [kpi_stock_utilisation, setKpi_stock_utilisation] = useState([{}]);
const stock_utilisation= useRef(0);
useEffect(() => {
axios.get("http://localhost:5137/KPI_Stock_Utilisation").then((response) => {
stock_utilisation.current = (response.data.length / 402) * 100;
setKpi_stock_utilisation(response.data);
});
//this will guarantee that the api will be called only once
}, []);
//you should see this twice, one with the value 0, and another one, the calculated data
console.log('component render',stock_utilisation.current)
return (
<div>
<p>{kpi_stock_utilisations}</p>
</div>
);
}
To note, if you call this component from more than one location, for sure it will render several times - keep that in mind.
On the other hand, all your variables should always start with a lower case and try to name your variables like this: instead of kpi_stock_utilisation change it to kpiStockUtilisation for a better coding practice
You got into infinite loop.
Its hard to explain why it doesn't work as expected, but I can try.
First of all, useEffect with empty array of dependencies works like componentDidMount and fires only after (!) first render.
So you have some value returned from your let kpi_stock_utilisations =KPI_Stock_Utilisation(); then it rendered, after this your useEffect fires a request and set state, setting of state trigger re-render and new value to return, this new value trigger your parent component to return let kpi_stock_utilisations =KPI_Stock_Utilisation(); might run again.
If you are trying to create a custom hook for fetching some info, follow rules of hooks
I hope it helped you

interval keeps going after clearinterval [duplicate]

I am trying to understand the useRef hook in React.
I have created a simple time in react . The code for which is available below.
import { useRef, useState, useEffect } from 'react';
function Parent() {
const [count,setCount]=useState(5);
const ref=useRef(0);
//let hold=0;
const countdown=()=>{
ref.current=setInterval(()=>{
// console.log('ref.current-->',ref.current);
setCount((c)=>c-1)
},1000)
}
useEffect(()=>{
if(count<1)
clearInterval(ref.current)
},[count])
return(
<>
<h3>Timer : {count}</h3>
<br/>
<button onClick={countdown}>countdown</button>
</>
)
}
export default Parent;
Here I have created a ref using the hook and I am monitoring the count state . When it hits 0 , I am calling the 'clearInteval' function to clear up the timer.
This code is working fine .
But when I try to do the same using a normal variable rather than the one created by the hook , the interval is not getting cleared .
Please find below the code for the same.
import { useRef, useState, useEffect } from 'react';
function Parent() {
const [count,setCount]=useState(5);
const ref=useRef(0);
let hold=0;
const countdown=()=>{
hold=setInterval(()=>{
// console.log('ref.current-->',ref.current);
setCount((c)=>c-1)
},1000)
}
useEffect(()=>{
if(count<1)
clearInterval(hold)
},[count])
return(
<>
<h3>Timer : {count}</h3>
<br/>
<button onClick={countdown}>countdown</button>
</>
)
}
export default Parent;
What am I not understanding here ?
This code should have worked in normal javaScript.
const myRef = useRef() will provide a ref object such that myRef.current's value will persist across renders. When you use let myVar = something, myVar will be re-created on each render, so you will lose and replace its value each time.
Your Parent component is getting re-rendered each time your state changes, so you benefit from keeping your interval reference as a ref from useRef.

Why My React Component Render Multiple Times In Console?

Im new in react.
I'm Created two file App.js and UseEffect.js
I'm Learn about lifecycle in react with function.
So When I See in console, that's render multiple time.
You can see my picture below.
My Console In Browser
This Is My Code
UseEffect.js
import React, {useState, useEffect} from "react";
function MyFunction(){
console.log('-> Function Init')
const [count, setCount] = useState(0)
const handleCount = () => {
setCount(prevState => {
return prevState+1
})
}
//LifeCycle
useEffect(() => {
console.log('my first effect')
})
console.log(`-> Start Render (${count})`)
return(
<div>
<h1>Function Component</h1>
<p>
<button onClick={handleCount}>Count</button>
{count}
</p>
</div>
)}
export default MyFunction
App.Js
import './App.css';
import UseEffect from './components/UseEffect'
function App() {
return (
<div className="App">
<UseEffect />
</div>
);
}
export default App;
How do it's work?, I Want it. it's just render one times.
Your useEffect call is missing a dependency array. When you want it to run only at the initial render, you need to pass it an empty array as its dependencies.
useEffect(() => {
console.log('my first effect')
}, [])
For further details, see this question.
Why it renders twice:
It's an intentional feature of the StrictMode. This only happens in development, and helps find accidental side effects put into the render phase. We only do this for components with Hooks because those are more likely to accidentally have side effects in the wrong place.
-gaearon
TLDR: It's a feature not a bug.

Invalid hook call error when trying to set state

I have a scenario where I am forced to call a trigger method to show a modal from two different places, one using a hotkey combination and another by clicking on a toolbar button. In order to do so I have the following code, where I call the triggerCustomLinkModal to set the state but then I am hit with the Invalid Hook call error.
import { useState, useCallback, useEffect } from "react"
import { Dialog } from "#blueprintjs/core"
const useLocalState = () => {
const [isShown, setIsShown] = useState(false)
const setState = useCallback((state) => {
setIsShown(state)
})
const getState = useCallback(() => {
return isShown
})
return {
setState,
getState
}
}
export const CustomLinkModalUI = () => {
const { getState } = useLocalState()
return (
<>
<Dialog isOpen={getState()} />
</>
)
}
export const triggerCustomLinkModal = () => {
const { setState } = useLocalState()
setState()
}
Expanding from Chris answer in the comments ( You can't use hooks outside React components. -> so you can't call useLocalState() inside triggerCustomLinkModal since triggerCustomLinkModal is not a React component ):
You don't really need the useCallback hook or even the functions itself. Aaccording to react docs :
Note
React guarantees that setState function identity is stable and won’t
change on re-renders. This is why it’s safe to omit from the useEffect
or useCallback dependency list.
This also means that using useCallback hook to set a state it doesn't really make sense (because useCallback role is just to return a memoized callback)
What you basically need is a state set up in the closest parrent component and pass the setIsShown as a prop as well as the isShown function.
Your current implementation, even if it weren't for the error, it wouldn't refer to the same state since on each useLocalState() you are initializing a fresh new state (so you are not pointing to the same state in CustomLinkModalUI and triggerCustomLinkModal)

Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. error

import React from 'react'
import axios from "axios"
import { useEffect } from "react"
import { useState } from "react"
export function Profile (){
const pathname = window.location.pathname
const[data,setData] = useState([])
const [loaded,hasloaded] = useState(false)
let username = pathname.split("/")[1]
useEffect(()=>{
axios.post('http://localhost:5000/profile/getProfile', {
"username":username
})
.then((res)=> setData(res.data))
})
return (
<div className='Wrapper'>
<img/>
{loaded ? <h2>{data[0].username}</h2>:<h2>Loading</h2>}
<img />
</div>
)
}
axios it taking like 10 seconds to get the response is this normal? when i request on postman it takes like 1 second. also how can i render when i have recieved the data without causing to many rerenders?
When the dependency array for useEffect is undefined (instead of an empty array) then the effect runs on every render. And within your useEffect you are updating state, which will trigger a re-render. This means every render triggers a re-render.
It looks like you only want the effect to run once, when the component first loads. For that, pass an empty dependency array to useEffect:
useEffect(()=>{
axios.post('http://localhost:5000/profile/getProfile', {
"username":username
})
.then((res)=> setData(res.data))
}, []); // <--- here

Categories

Resources