updating a state immediately using react hooks [duplicate] - javascript

This question already has answers here:
console log the state after using useState doesn't return the current value [duplicate]
(3 answers)
React hooks states aren't updating in log
(2 answers)
Closed 2 years ago.
I am trying to update a state after a trigger and want to use the state immediately for a function to trigger but the state is not updated immediately .
any suggestions ?
<Button
onClick={() => {
console.log(finalData) //old data
setFinalData(mutableData); // updating state
console.log(finalData) // still geeting old state
}>
</Button>

setFinalData is kind of async behaviour, so if you :
console.log(finalData) //old data
setFinalData(mutableData); // <----- async behavior
console.log(finalData) // you will never get updated finalData directly here
Solution : useEffect
useEffect(() => {
// you will get updated finalData here, each time it changes
console.log(finalData);
// you can trigger your function from here
},[finalData]);
Here is code snippet, hope this will clear your doubts :
const { useState , useEffect } = React;
const App = () => {
const [finalData,setFinalData] = useState([]);
useEffect(() => {
setTimeout(() => {
setFinalData([...finalData, "Vivek" , "Darshita"]);
console.log("finalData -----> not updated right after" ,finalData);
},2000);
},[]);
useEffect(() => {
if(finalData.length)
console.log("Final data updated , invoke your function" , finalData)
},[finalData]);
return (
<div>
{ finalData.map(user => <p>{user}</p>) }
</div>
);
}
ReactDOM.render(<App />, document.getElementById('react-root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

Related

UseCallback in combination with StrictMode [duplicate]

This question already has answers here:
Why useEffect running twice and how to handle it well in React?
(2 answers)
Closed 9 months ago.
I have the following code snippet in use while wrapping my whole React application with <React.StrictMode>.
function Quiz() {
const fetchData = useCallback(
async () => {
console.log("hiho");
},
[]
);
useEffect(() => {
fetchData();
}, [fetchData])
return (
<>
</>
)
}
For the initial load of my application fetchData is being called twice within my useEffect(). I am a bit puzzled as I assumed that useCallback() would prevent this (even though StrictMode calls the rendering twice).
Should I be worried that fetchData get's called twice? In my case fetchData returns random data which then has the side effect that the data changes during the render process on dev.
Try removing the fetchData from the useEffect dependency array. I believe that should render it just once.
function Quiz() {
const fetchData = useCallback(
async () => {
console.log("hiho");
},
[]
);
useEffect(() => {
fetchData();
}, [])
return (
<>
</>
)
}

React setState isn't setting state inside useEffect [duplicate]

This question already has answers here:
Arrow function VS normal function in Array.map()
(2 answers)
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
(4 answers)
Closed 12 months ago.
I'm pretty new to hooks and I'm trying to use setState for data I'm getting back from an API, but the state never updates. I only need to make the call when the component mounts, which is why the second argument in my useEffect is an empty array. I can see that I'm getting back the data when I console.log the response, it just isn't being set.
const [routeOptions, setRouteOptions] = useState()
useEffect(() => {
Axios.get("https://svc.metrotransit.org/NexTrip/Routes?format=json").then(response => {
const routes = response.data
setRouteOptions(routes)
});
}, []);
I then try to map through the data like so:
{routeOptions && routeOptions.map(option => {
<option>
{option.description}
</option>
})}
but because my state never got set there's nothing to map through.
I may be missing something super obvious cause I'm not familiar with hooks, so any help is appreciated!
You need to return a value from your .map(). Make sure to give your <option> a unique key prop as well.
Note also that the route property Description has a capital D :)
<select>
{routeOptions.map((option) => {
return <option key={option.Route}>{option.Description}</option>;
})}
</select>
here it is all together
import { useState, useEffect } from "react";
import Axios from "axios";
export default function Test() {
const [routeOptions, setRouteOptions] = useState(null);
useEffect(() => {
Axios.get("https://svc.metrotransit.org/NexTrip/Routes?format=json").then(
(response) => {
const routes = response.data;
setRouteOptions(routes);
}
);
}, []);
if (!routeOptions)
return (
<div>
<p>Loading...</p>
</div>
);
return (
<select>
{routeOptions.map((option) => {
return <option key={option.Route}>{option.Description}</option>;
})}
</select>
);
}
try to use Async-select https://react-select.com/async and make a function that returns an array of pair {label, value} instead of wasting your time stuck here.

What is the difference between these two functions 'foo1' and 'foo2'? [duplicate]

This question already has answers here:
What does arrow function '() => {}' mean in Javascript? [duplicate]
(2 answers)
Closed 1 year ago.
function foo1() {
return {
bar: "hello"
};
}
function foo2() {
return {
bar: "hello";
}
}
There is two functions 'foo1' and 'foo2' what will be the possible output and what is key difference between these functions.
Preface: As shown, both will cause infinite re-renders. The setState calls should only be in reaction to something else happening.
setState(state + 1) uses the in-scope value of state (which might be stale), adds one, and sets that as the new value. If state is stale (the actual state value has been updated in the meantime), that will overwrite a previous update.
setState(state => state + 1) asks setState to call it back with the guaranteed-up-to-date version of state, adds one to it, and then sets that as the value.
Either is fine in an appropriate situation, but typically you want the second (callback) form, not the first, when updating state based on existing state.
More here in the React documentation.
Here's a contrived example demonstrating the difference using a stale state1 value:
const {useState, useEffect} = React;
const Example = () => {
const [state1, setState1] = useState(0);
const [state2, setState2] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
// THIS IS INCORRECT (for this situation), it uses a stale value
// of `state1`
setState1(state1 + 1);
// This is correct (for this situation)
setState2(state2 => state2 + 1);
}, 500);
return () => {
clearInterval(timer);
};
}, []);
return <div>
<div>state1 = {state1}</div>
<div>state2 = {state2}</div>
</div>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
There are some tools (like ESLint w/appropriate plugins) that will warn you about some situations where you're using stale state variables; for instance, ESLint's exhaustive-deps rule from eslint-plugin-react-hooks would issue a warning above that state1 was missing from the useEffect dependencies array.

How to prevent infinite re-rendering with useEffect() in React [duplicate]

This question already has answers here:
react useEffect comparing objects
(7 answers)
Closed 2 years ago.
I have an app that checks the user id on startup and loads the list of todo items based on the user logged in. I have the useEffect change only when data changes, but I have setData in the body of useEffect() meaning data changes and it re-runs infinitum.
However if I change [data] to [] in the second parameter, then it renders once BUT I have to refresh the page everytime I add a todo item for it to render rather than it render automatically. How can I have it render automatically without looping infinitely?
const [data, setData] = useState([])
useEffect(() => {
UserService.getUserById(localStorage.getItem("userId")).then(res => {
if (res.data !== null) {
setData(res.data.todos)
}
})
}, [data])
You can add a condition in the call back function that checks if a certain condition is met, e.g. if data is empty. If it is empty, then fetch data, otherwise do nothing. This will prevent the infinite loop from happening.
const getData = useEffect(()=>{
const fetchData = () => {
UserService.getUserById(localStorage.getItem("userId"))
.then(res => {
if (res.data !== null) {
setData(res.data.todos)
}
})
.catch(error => {
// do something with error
})
}
if (data.length === 0)
fetchData()
},[data]);
Alternatively, you use an empty dependency array so that the callback function in the useEffect is called once.
useCallback Hook can be used with slight modifications in your code.
You will need to import useCallback from "react" first.
import {useCallback} from "react";
And then use this useCallback around our getData function. (Have modified the answer a bit)
const getData = useCallback(()=>{
UserService.getUserById(localStorage.getItem("userId")).then(res => {
if (res.data !== null) {
setData(res.data.todos)
}
})
},[data]);
useEffect(() => {
getData();
}, [data])
This React Hook will make sure that the getData() function is only created when the second argument data changes.
In your code UserService.getUserById(localStorage.getItem("userId")) return a promise and it get data one time so you just have to call getUserById one time at the time of load by using [] and if you want to call it again make a function and use it wherever on refresh function or on adding todos item or update or delete function. Otherwise you have to use observable or useCallBack hook
You need to pass the reset param to prevent loop. once callback trigger reset value false. so that execution not running again until reset the value
Codesanbox
export default function App() {
let i = 1;
const [data, setData] = useState([]);
const [reset, setReset] = useState(true);
useEffect(() => {
if (reset) {
setTimeout(() => {
//callback
setReset(false);
setData(Math.random());
}, 1000);
}
}, [data]);
return (
<div className="App">
<h1>{data}</h1>
<button
onClick={() => {
setReset(true);
setData("");
}}
>
Click this and see the data render again. i just reset the data to empty
</button>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
Use a condition to stop the loop by setting a condition to stop it. You can check if a certain value is set or check if there are any values sent at all.

useEffect has a missing dependency: 'user' [duplicate]

This question already has answers here:
Unable to copy array using setstate hook
(3 answers)
Where should I declare functions that are called inside a useEffect() hook?
(2 answers)
Closed 2 years ago.
I have a certain query string I am looking for and when that gets passed on page loading I need to update my user's status to "premium". I have:
useEffect(() => {
const queryString = require('query-string');
const values = queryString.parse(window.location.search);
console.log('before' + user.premium);
if (values.premium !== ''){
setUser({...user, premium: true});
}
console.log('after' + user.premium);
}, []);
I am using React functional components and my user is an object that contains many other values, in addition to "premium" key. From what I understand, passing the empty array [] will cause useEffect to run only on page load. Doing so, however, I get an error:
React Hook useEffect has a missing dependency: 'user'.. BUT, when I include user in that array, the page continually reloads (since I am updating the value of it). I've also tried passing in setUser and that didn't work.
You can pass properties of object as dependencies for useEffect. I have created a working sandbox here.
Also, don't worry to much about the eslint rule react-hooks/exhaustive-deps, view it as more of a guideline and don't be afraid to add a eslint-disable-next-line if it is pushing you to add dependencies that you don't think should be added.
import React, { useEffect, useState } from "react";
export default function App() {
const [user, setUser] = useState({ count: 0, premium: false });
useEffect(() => {
console.log("when component mounts");
}, []);
useEffect(() => {
console.log("when component updates");
});
useEffect(() => {
console.log("when premium changes");
}, [user.premium]);
return (
<div>
<p>Count: {user.count}</p>
<p>Premium: {user.premium}</p>
<button
onClick={() => setUser((prev) => ({ ...prev, count: prev.count + 1 }))}
>
Increment Count
</button>
<button
onClick={() => setUser((prev) => ({ ...prev, premium: !prev.premium }))}
>
Toggle premium
</button>
</div>
);
}

Categories

Resources