Cannot Update A Component While Rendering A Different Component Warning
Solution 1:
This warning was introduced since React V16.3.0.
If you are using functional components you could wrap the setState call into useEffect.
Code that does not work:
constHomePage = (props) => {
props.setAuthenticated(true);
consthandleChange = (e) => {
props.setSearchTerm(e.target.value.toLowerCase());
};
return (
<divkey={props.restInfo.storeId}className="container-fluid"><ProductListsearchResults={props.searchResults} /></div>
);
};
Now you can change it to:
constHomePage = (props) => {
// trigger on component mountuseEffect(() => {
props.setAuthenticated(true);
}, []);
consthandleChange = (e) => {
props.setSearchTerm(e.target.value.toLowerCase());
};
return (
<divkey={props.restInfo.storeId}className="container-fluid"><ProductListsearchResults={props.searchResults} /></div>
);
};
Solution 2:
Just coming here because I just had this issue and it took me a bit of digging around before I realised what I'd done wrong - I just wasn't paying attention to how I was writing my functional component.
Figured I'd leave an answer here in case anyone comes looking, and they made the same simple mistake that I did.
I was doing this:
constLiveMatches = (props: LiveMatchesProps) => {
const {
dateMatches,
draftingConfig,
sportId,
getDateMatches,
} = props;
if (!dateMatches) {
const date = newDate();
getDateMatches({ sportId, date });
};
return (<div>{component stuff here..}</div>);
};
I had just forgotten to use useEffect
before dispatching my redux call of getDateMatches()
So stupid and something I had been doing in every other component, haha.
So it should have been:
constLiveMatches = (props: LiveMatchesProps) => {
const {
dateMatches,
draftingConfig,
sportId,
getDateMatches,
} = props;
useEffect(() => {
if (!dateMatches) {
const date = newDate();
getDateMatches({ sportId, date });
}
}, [dateMatches, getDateMatches, sportId]);
return (<div>{component stuff here..}</div>);
};
Simple and silly mistake, but took a while to realise it, so hopefully this helps out someone else with this issue.
Solution 3:
I fixed this issue by removing the dispatch from the register components render method to the componentwillunmount method. This is because I wanted this logic to occur right before redirecting to the login page. In general it's best practice to put all your logic outside the render method so my code was just poorly written before. Hope this helps anyone else in future :)
My refactored register component:
classRegisterextendsComponent {
componentWillUnmount() {
// Reset register status to allow return to register pageif ( this.props.registerStatus !== "" ) this.props.dispatch( resetRegisterStatus() )
}
render() {
if( this.props.registerStatus === SUCCESS ) {
return<Redirectpushto = {LOGIN}/>
}
return (
<divstyle = {{paddingTop: "180px", background: 'radial-gradient(circle, rgba(106,103,103,1) 0%, rgba(36,36,36,1) 100%)', height: "100vh"}}><RegistrationForm/></div>
);
}
}
Solution 4:
If useEffect
cannot be used in your case or if the error is NOT because of Redux
I used setTimeout
to redirect one of the two useState
variables to the callback queue.
I have one parent and one child component with useState
variable in each of them. The solution is to wrap useState
variable using setTimeout
:
setTimeout(() =>SetFilterData(data), 0);
Example below
Parent Component
importExpenseFilterfrom'../ExpensesFilter'functionExpensesView(props) {
const [filterData, SetFilterData] = useState('')
constGetFilterData = (data) => {
// SetFilterData(data);//*****WRAP useState VARIABLE INSIDE setTimeout WITH 0 TIME AS BELOW.*****setTimeout(() =>SetFilterData(data), 0);
}
const filteredArray = props.expense.filter(expenseFiltered =>
expenseFiltered.dateSpent.getFullYear().toString() === filterData);
return (
<Window>
<div>
<ExpenseFilterFilterYear = {GetFilterData}></ExpenseFilter>
Child Component
const ExpensesFilter = (props) => {
const [filterYear, SetFilterYear] = useState('2022')
const FilterYearListener = (event) => {
event.preventDefault()
SetFilterYear(event.target.value)
}
props.FilterYear(filterYear)
return (
Solution 5:
TL;DR;
For my case, what I did to fix the warning was to change from useState
to useRef
react_devtools_backend.js:2574Warning: Cannotupdateacomponent (`Index`) whilerenderingadifferentcomponent (`Router.Consumer`). TolocatethebadsetState() callinside `Router.Consumer`, followthestacktraceasdescribedinhttps://reactjs.org/link/setstate-in-renderatRoute (http://localhost:3000/main.bundle.js:126692:29)
at Index (http://localhost:3000/main.bundle.js:144246:25)
at Switch (http://localhost:3000/main.bundle.js:126894:29)
at Suspense
at App
at AuthProvider (http://localhost:3000/main.bundle.js:144525:23)
at ErrorBoundary (http://localhost:3000/main.bundle.js:21030:87)
at Router (http://localhost:3000/main.bundle.js:126327:30)
at BrowserRouter (http://localhost:3000/main.bundle.js:125948:35)
at QueryClientProvider (http://localhost:3000/main.bundle.js:124450:21)
The full code for the context of what I did (changed from the lines with // OLD:
to the line above them). However this doesn't matter, just try changing from useState
to useRef
!!
import { HOME_PATH, LOGIN_PATH } from'@/constants';
import { NotFoundComponent } from'@/routes';
importReactfrom'react';
import { Redirect, Route, RouteProps } from'react-router-dom';
import { useAccess } from'@/access';
import { useAuthContext } from'@/contexts/AuthContext';
import { AccessLevel } from'@/models';
typeProps = RouteProps & {
component: Exclude<RouteProps['component'], undefined>;
requireAccess: AccessLevel | undefined;
};
exportconstIndex: React.FC<Props> = (props) => {
const { component: Component, requireAccess, ...rest } = props;
const { isLoading, isAuth } = useAuthContext();
const access = useAccess();
const mounted = React.useRef(false);
// OLD: const [mounted, setMounted] = React.useState(false);return (
<Route
{...rest}
render={(props) => {
// If in indentifying authentication state as the page initially loads, render a blank page
if (!mounted.current && isLoading) return null;
// OLD: if (!mounted && isLoading) return null;
// 1. Check Authentication is one step
if (!isAuth && window.location.pathname !== LOGIN_PATH)
return <Redirectto={LOGIN_PATH} />;
if (isAuth && window.location.pathname === LOGIN_PATH)
return <Redirectto={HOME_PATH} />;
// 2. Authorization is another
if (requireAccess && !access[requireAccess])
return <NotFoundComponent />;
mounted.current = true;
// OLD: setMounted(true);
return <Component {...props} />;
}}
/>
);
};
exportdefaultIndex;
Post a Comment for "Cannot Update A Component While Rendering A Different Component Warning"