I need to setState with an object that I'm getting from a redux store. The problem is when I call setState in my component I am getting undefined. Any idea on how to set a default value of state with fetched data?
Here is my component:
import React, { useEffect, Fragment, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
const contactDetails = useSelector((state) => state.contactDetails)
const upFields = contactDetails?.contact?.data?.fields
const [contact, setContact] = useState({
fields: upFields <---- this is returning undefined.. The name is correct, but maybe setState is running too fast?
})
console.log(contact) <---- this shows {fields: undefined}
console.log(upFields) <---- this console.logs just fine
you use useEffect() and trigger it using the object
useEffect(()=>{
setContact(fetched_data)
}, [fetched_data]) // <-- data array will trigger every time this data change
you can trigger it on first component mount with
useEffect(()=>{
setContact(fetched_data)
}, []) // <-- empty array will only trigger once
So, I ended up setting my state one component higher, and passing the "upFields" to the child component that needed this state. Once in the child component I just ran a useEffect and setState with the data I needed
Related
i wanna ask about my case using useEffect Hook and put on params with useSelector. i really don't know about this infinite loop after i put on my variables contains useSelector that have bunch of data array from redux. I have intention to put on that variables on parameter useEffect, because i want to directly update data and the data display on the same page.
// this itemGroup have all of data from getGroup
const itemGroup = useSelector(selectGroup);
//this function call get api Data and dispatch to initial state
const callFunction = () => {
dispatch(getGroup());
};
useEffect(() => {
callFunction();
// this console.log getting infinite loop after put on itemGroup as parameter useEffect
console.log()
}, [itemGroup]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
it is because you pass your store state as a dependency to useEffect. On updating the store state you are dispatching the action named callFunction which might be updating your store state again, which triggers useEffect and useEffect again dispatch callFunction which creates a loop.
just pass empty array to useEffect:
useEffect( () =>{ callFunction() },[])
I'm studying React hooks but i am not able to understand why I got this output in the console. Someone with great heart could explain in detail the "running execution" oh these hooks?
import { useState, useEffect } from "react";
function Homepage() {
const [state, setState] = useState();
useEffect(() => {
console.log("useEffect");
console.log("useEffect not executed");
setState("hello")
}, []);
if (!state) {
console.log("state not defined");
return <div>State undefined</div>;
}
return <div>ciao</div>;
}
export default Homepage;
console output:
state not defined
state not defined
useEffect
useEffect not executed
useEffect
useEffect not executed
Basically it's a combination of React.StrictMode double invoking the function body twice as a way to help you detect unexpected side-effects
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method
Function component bodies <-- this
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
remounting the component to ensure reusable state
To help surface these issues, React 18 introduces a new
development-only check to Strict Mode. This new check will
automatically unmount and remount every component, whenever a
component mounts for the first time, restoring the previous state on
the second mount.
and the useEffect hook being called at the end of the render cycle.
function Homepage() {
const [state, setState] = useState();
useEffect(() => {
console.log("useEffect"); // logs second as expected side-effect
console.log("useEffect not executed");
setState("hello");
}, []);
if (!state) {
console.log("state not defined"); // logs first as unintentional side-effect
return <div>State undefined</div>;
}
return <div>ciao</div>;
}
...
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import Homepage from "./Homepage";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<Homepage />
</StrictMode>
);
Explaining the logs
console output:
state not defined // <-- initial render
state not defined // <-- double invocation of function body
useEffect // <-- effect at end of initial render
useEffect not executed // <-- effect at end of initial render
...unmount/mount
useEffect // <-- effect at end of render
useEffect not executed // <-- effect at end of render
useEffect runs when the page renders and the other functions execute before useEffect so your code runs the if (!state) first then useEffect runs and state sets to "hello"; here is a link to fully understand useEffect hook: useEffect; Good luck;
your if statement is running before the useEffect even tho is after it, you need to put both divs inside the return and remove the if
return (
{!state ? <div>State undefined</div> : <div>ciao</div>}
)
state not defined first render of your component Homepage
state not defined 2nd render
useEffect useEffect not executed your component is mounted, so the useEffect hook is triggered.
useEffect useEffect not executed here your component rerender with the state hello the useEffect hook is triggered again
In practice, useEffect hook runs at minimum following your dependency array. Here your set [] so the useEffect hook runs when the component mounts, but sometimes it can still be triggered.
I am trying to create a React Functional Component using Typescript that will get data from an API and then send that data to another component, however, I am getting an error of "Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."
Please offer any advice!
useEffect(() => {
await axios.get('https://quote-garden.herokuapp.com/api/v3/quotes/random').then((resp) => {
setQuote1(resp.data.data[0]);
});
getQuote();
}, []);
Snippet of Code Causing Error
EDIT:
Here is the entire File where the error is occurring.
import React, { useEffect, useState } from 'react';
import { Row, Col, CardGroup } from 'reactstrap';
import axios from 'axios';
import QuoteCard from './QuoteCard';
const MainQuotes = () => {
const [quote1, setQuote1] = useState();
useEffect(() => {
await axios.get('https://quote-garden.herokuapp.com/api/v3/quotes/random').then((resp) => {
setQuote1(resp.data.data[0]);
});
getQuote();
}, []);
return (
<Row>
<Col>
<CardGroup>
<QuoteCard quoteData={quote1} />
</CardGroup>
</Col>
</Row>
);
};
export default MainQuotes;
Depending on the type of quote1 (I'm assuming it's a string) update to:
const [quote1, setQuote1] = useState('')
useEffect(() => {
function fetchQuote() {
await axios.get('https://quote-garden.herokuapp.com/api/v3/quotes/random')
.then((resp) => {
setQuote1(resp.data.data[0]);
});
}
if (!quote1) {
fetchQuote();
}
}, []);
Because the response from the API is a random quote, you have to handle it based on the value of quote1. This should work because quote1 will only be updated after the component mounts (when the value is an empty string), and the following render won't update state, so useEffect won't loop infinitely.
Before the edit, I assumed the axios request was inside of the getQuote function. I have updated my answer to reflect the code you have posted.
If the API response was static, because the items in the dependency array only cause a re-render if they are changed from their current value, it only causes a re render immediately after the first state update.
Can we get your entire code please? It seems the problem is going to be with your state hook and figuring out exactly what its doing.
My guess as of now is your state hook "setQuote1" is being invoked in a way that causes a re-render, which then would invoke your useEffect() again (as useEffect runs at the end of the render cycle) and thus, calling upon your setQuote1 hook again. This repeats itself indefinitely.
useEffect() allows for dependencies and gives you the power to tell exactly when useEffect() should be invoked.
Example: useEffect(() { code here }, [WATCH SPECIFICALLY THIS AND RUN ONLY WHEN THIS UPDATES]).
When you leave the dependency array empty, you tell the hook to run whenever ANYTHING updates state. This isn't necessarily bad but in some cases you only want your useEffect() to run when a specific state updates.
Something in your application must be triggering your useEffect() hook to run when you aren't wanting it to.
Hi I'm learning React now and having trouble with the state..
I know when the state changes, the component re-renders and the code in UseEffect widout depth only runs once.
But I can't explain exactly why infinite rendering occurs when I write setState in JSX or in the render syntax.
below code causes infinite re-render
import React, { useState, useEffect } from 'react'
const index = () => {
const [active, setActive] = useState(false);
console.log("render", active);
setActive(false);
return (
<div>
</div>
)
}
export default index
But the code below has no problem even though it keeps calling setState.
import React, { useState, useEffect } from 'react'
const index = () => {
const [active, setActive] = useState(false);
console.log("render", active);
useEffect(() => {
setInterval(()=>{
console.log("run")
setActive(true)
},0);
}, [])
return (
<div>
</div>
)
}
Does setState trigger re-rendering regardless of state value?
I want to know the exact reason why using setState outside of useEffect causes an error.
This is happening because, in the first case, when useEffect is not used,
you are updating your state right after declaring it.
Even if you are setting the state as false again, but for react, the state has been updated. And the first rule of thumb for react is, if state update happens, component will re render.
This is why you are getting an infinite rerendering.
your code is following the below flow:
Declare state variable and pass value as false
Update state to false
State updated, hence component re rendered.
Step 1 again.
In second case, where use effect is used, your state will update only when the component is mounted, which means, after that any state update won't trigger your useEffect.
Based on React documentation: https://reactjs.org/docs/hooks-reference.html#usestate
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
And there is an addition: https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update
If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.) Note that React may still need to render that specific component again before bailing out.
And here is the important part: React may still need to render that specific component again before bailing out.
So yes, the component may still rerender even if the values are the same.
I am trying to use useState inside useEffect. I want to access and modify a state inside it( useEffect ), here named as isAuth and according to the new state render the component.
import React, { useState, useEffect } from 'react';
const Authentication = () => {
const [isAuth, setIsAuth] = useState(false);
useEffect(() => {
console.log(isAuth);
setIsAuth(true);
console.log(isAuth);
}, [isAuth]);
return <div>{isAuth ? <p>True</p> : <p>False</p>}</div>;
};
export default Authentication;
The thing is in console I am getting false, false, true, true.Instead of this console, I expected the 2nd console message to be true. Can someone explain it how it happens and how do I actually change the state before component renders?
setIsAuth doesn't cause the local variableisAuth to change its value. const data values can't be changed, and even if you defined it as let, that's not what setting state does. Instead, when you set state, the component rerenders. On that new render, the call to useState will return the new value, and you can use that new value for the new render.
The component renders for the first time. Then it runs the effect. The closure for the effect has the local variables from that first render, and your code uses those variables to log the false twice. Since you called set state, a new render will happen, and that new render will have different variables. When it's effect runs, it will log true twice, since that's the values in its closure.
Here are some comments in the code explaining how React setState will only update the local const once the component re-renders
import React, { useState, useEffect } from 'react';
const Authentication = () => {
// React will initialise `isAuth` as false
const [isAuth, setIsAuth] = useState(false);
useEffect(() => {
// Console log outputs the initial value, `false`
console.log(isAuth);
// React sets state to true, but the new state is not available until
// `useState` is called on the next render
setIsAuth(true);
// `isAuth` will remain false until the component re-renders
// So console.log will output `false` again the first time this is called
console.log(isAuth);
}, [isAuth]);
// The first time this is rendered it will output <p>False</p>
// There will be a re-render after the `setState` call and it will
// output <p>True</p>
return <div>{isAuth ? <p>True</p> : <p>False</p>}</div>;
};
export default Authentication;
That's actually correct. useEffect lets you access the latest state after an update. So during the first render, what you see is basically the initial state, no matter if you update it.
Calling setState inside useEffect will cause a rerender with the new state (isAuth = true), which will result in calling useEffect again. At this point, the new logged state is true.