我在反应中收到此警告:
index.js:1 Warning: Cannot update a component (`ConnectFunction`)
while rendering a different component (`Register`). To locate the
bad setState() call inside `Register`
我转到了堆栈跟踪中指示的位置,并删除了所有设置状态,但是警告仍然存在。可能是由于redux派发而发生的吗?
我的代码:
register.js
class Register extends Component {
render() {
if( this.props.registerStatus === SUCCESS) {
// Reset register status to allow return to register page
this.props.dispatch( resetRegisterStatus()) # THIS IS THE LINE THAT CAUSES THE ERROR ACCORDING TO THE STACK TRACE
return <Redirect push to = {HOME}/>
}
return (
<div style = {{paddingTop: "180px", background: 'radial-gradient(circle, rgba(106,103,103,1) 0%, rgba(36,36,36,1) 100%)', height: "100vh"}}>
<RegistrationForm/>
</div>
);
}
}
function mapStateToProps( state ) {
return {
registerStatus: state.userReducer.registerStatus
}
}
export default connect ( mapStateToProps ) ( Register );
在我的registerForm.js调用的registerForm组件中触发警告的函数
handleSubmit = async () => {
if( this.isValidForm() ) {
const details = {
"username": this.state.username,
"password": this.state.password,
"email": this.state.email,
"clearance": this.state.clearance
}
await this.props.dispatch( register(details) )
if( this.props.registerStatus !== SUCCESS && this.mounted ) {
this.setState( {errorMsg: this.props.registerError})
this.handleShowError()
}
}
else {
if( this.mounted ) {
this.setState( {errorMsg: "Error - registration credentials are invalid!"} )
this.handleShowError()
}
}
}
Stacktrace:
答案 0 :(得分:23)
此警告是从React V16.3.0开始引入的。
。如果您正在使用功能组件,则可以将setState调用包装到useEffect中。
无效的代码:
const HomePage = (props) => {
props.setAuthenticated(true);
const handleChange = (e) => {
props.setSearchTerm(e.target.value.toLowerCase());
};
return (
<div key={props.restInfo.storeId} className="container-fluid">
<ProductList searchResults={props.searchResults} />
</div>
);
};
现在您可以将其更改为:
const HomePage = (props) => {
useEffect(() => {
props.setAuthenticated(true);
});
const handleChange = (e) => {
props.setSearchTerm(e.target.value.toLowerCase());
};
return (
<div key={props.restInfo.storeId} className="container-fluid">
<ProductList searchResults={props.searchResults} />
</div>
);
};
最好的问候
答案 1 :(得分:10)
来到这里是因为我刚刚遇到了这个问题,在我意识到自己做错了什么之前,我花了一些心思——我只是没有注意我是如何编写我的功能组件的。
我想我会在这里留下一个答案,以防有人来找,他们犯了和我一样的简单错误。
我是这样做的:
const LiveMatches = (props: LiveMatchesProps) => {
const {
dateMatches,
draftingConfig,
sportId,
getDateMatches,
} = props;
if (!dateMatches) {
const date = new Date();
getDateMatches({ sportId, date });
};
return (<div>{component stuff here..}</div>);
};
我刚刚忘记在发送 useEffect
的 redux 调用之前使用 getDateMatches()
太愚蠢了,我在其他组件中一直在做的事情,哈哈。
所以应该是:
const LiveMatches = (props: LiveMatchesProps) => {
const {
dateMatches,
draftingConfig,
sportId,
getDateMatches,
} = props;
useEffect(() => {
if (!dateMatches) {
const date = new Date();
getDateMatches({ sportId, date });
}
}, [dateMatches, getDateMatches, sportId]);
return (<div>{component stuff here..}</div>);
};
简单而愚蠢的错误,但花了一段时间才意识到,所以希望这能帮助其他人解决这个问题。
答案 2 :(得分:5)
我通过从寄存器组件的render方法中删除了派遣到componentwillunmount方法的方法来解决了这个问题。这是因为我希望在重定向到登录页面之前立即执行此逻辑。通常,最佳做法是将所有逻辑放在render方法之外,这样我的代码之前就写得不好。希望这对以后的其他人有帮助:)
我的重构寄存器组件:
class Register extends Component {
componentWillUnmount() {
// Reset register status to allow return to register page
if ( this.props.registerStatus !== "" ) this.props.dispatch( resetRegisterStatus() )
}
render() {
if( this.props.registerStatus === SUCCESS ) {
return <Redirect push to = {LOGIN}/>
}
return (
<div style = {{paddingTop: "180px", background: 'radial-gradient(circle, rgba(106,103,103,1) 0%, rgba(36,36,36,1) 100%)', height: "100vh"}}>
<RegistrationForm/>
</div>
);
}
}
答案 3 :(得分:1)
这花了很多时间,但我能够解决这个问题,因为我们的架构主要是类组件,而且 useState 不可用。
修复方法是使用简单的超时(同样,这仅在您使用类组件时适用)
setTimeout(() => <problematic dispatch goes here>, 0);
这将推入事件循环。无论哪种方式,这仍然是一个笨拙的解决方案。我宁愿将其转换为功能组件并用 useState() 将其包围,或者通常避免使用该架构
答案 4 :(得分:1)
TL;DR;
就我而言,我为修复警告所做的是将 useState
更改为 useRef
react_devtools_backend.js:2574 Warning: Cannot update a component (`Index`) while rendering a different component (`Router.Consumer`). To locate the bad setState() call inside `Router.Consumer`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
at Route (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)
我所做工作的上下文的完整代码(从带有 // OLD:
的行更改为它们上方的行)。不过这无所谓,试试把useState
改成useRef
!!
import { HOME_PATH, LOGIN_PATH } from '@/constants';
import { NotFoundComponent } from '@/routes';
import React from 'react';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { useAccess } from '@/access';
import { useAuthContext } from '@/contexts/AuthContext';
import { AccessLevel } from '@/models';
type Props = RouteProps & {
component: Exclude<RouteProps['component'], undefined>;
requireAccess: AccessLevel | undefined;
};
export const Index: 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 <Redirect to={LOGIN_PATH} />;
if (isAuth && window.location.pathname === LOGIN_PATH)
return <Redirect to={HOME_PATH} />;
// 2. Authorization is another
if (requireAccess && !access[requireAccess])
return <NotFoundComponent />;
mounted.current = true;
// OLD: setMounted(true);
return <Component {...props} />;
}}
/>
);
};
export default Index;
答案 5 :(得分:0)
我遇到了同样的问题,对我有用的修复是如果你在做
<块引用>setParams/setOptions
在 useEffect 之外,则发生此问题。所以尽量在useEffect里面做这样的事情。它会像魅力一样工作
答案 6 :(得分:-1)
这太疯狂了。但是请尝试禁用Redux开发工具...由于Redux开发工具,我在一个不错的代码上显示了此警告。我查看了为什么我的动作多次触发后才发现,即使我只调度了一次。 Redux reducer running multiple times when unused action is first dispatched