Tam*_*jid 71 javascript reactjs redux
我在反应中收到此警告:
index.js:1 Warning: Cannot update a component (`ConnectFunction`)
while rendering a different component (`Register`). To locate the
bad setState() call inside `Register`
Run Code Online (Sandbox Code Playgroud)
我去了堆栈跟踪中指示的位置并删除了所有设置状态,但警告仍然存在。这可能发生在 redux dispatch 中吗?
我的代码:
注册.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 );
Run Code Online (Sandbox Code Playgroud)
在 register.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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪:
小智 89
这个警告是从 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>
);
};
Run Code Online (Sandbox Code Playgroud)
现在您可以将其更改为:
const HomePage = (props) => {
// trigger on component mount
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>
);
};
Run Code Online (Sandbox Code Playgroud)
shi*_*z27 69
请仔细阅读错误消息。我的指向具有错误 setState 的 SignIn 组件。我有一个 onPress 不是 Arrow function。
事情是这样的:
onPress={navigation.navigate("Home", { screen: "HomeScreen" })}
Run Code Online (Sandbox Code Playgroud)
我把它改成这样:
onPress={() => navigation.navigate("Home", { screen: "HomeScreen" }) }
Run Code Online (Sandbox Code Playgroud)
我的错误消息是:
ForwardRef(BaseNavigationContainer)警告:渲染不同组件 ( ) 时无法更新组件(SignIn)。要找到内部错误的 setState() 调用 ,请遵循 SignIn 中https://reactjs.org/link/setstate-in-renderSignIn中所述的堆栈跟踪 (位于 SignInScreen.tsx:20)
Spi*_*iff 23
我认为这很重要。是出自这个帖子@Red-Baron
@machineghost:我认为您误解了该消息所警告的内容。
将回调传递给子级以更新父级中的状态并没有什么问题。一直都这样就好了
问题是当一个组件在另一个组件中排队更新,而第一个组件正在渲染时。
换句话说,不要这样做:
function SomeChildComponent(props) {
props.updateSomething();
return <div />
}
Run Code Online (Sandbox Code Playgroud)
但这很好:
function SomeChildComponent(props) {
// or make a callback click handler and call it in there
return <button onClick={props.updateSomething}>Click Me</button>
}
Run Code Online (Sandbox Code Playgroud)
而且,正如 Dan 多次指出的那样,在渲染时在同一组件中排队更新也很好:
function SomeChildComponent(props) {
const [number, setNumber] = useState(0);
if(props.someValue > 10 && number < 5) {
// queue an update while rendering, equivalent to getDerivedStateFromProps
setNumber(42);
}
return <div>{number}</div>
}
Run Code Online (Sandbox Code Playgroud)
小智 18
如果useEffect无法在您的情况下使用或者错误不是由于 Redux 造成的
我曾经setTimeout将两个useState变量之一重定向到回调队列。
我有一个父组件和一个子组件,useState每个组件中都有变量。解决方案是使用以下方法包装useState变量setTimeout:
setTimeout(() => SetFilterData(data), 0);
Run Code Online (Sandbox Code Playgroud)
下面的例子
父组件
import ExpenseFilter from '../ExpensesFilter'
function ExpensesView(props) {
const [filterData, SetFilterData] = useState('')
const GetFilterData = (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>
<ExpenseFilter FilterYear = {GetFilterData}></ExpenseFilter>
Run Code Online (Sandbox Code Playgroud)
子组件
const ExpensesFilter = (props) => {
const [filterYear, SetFilterYear] = useState('2022')
const FilterYearListener = (event) => {
event.preventDefault()
SetFilterYear(event.target.value)
}
props.FilterYear(filterYear)
return (
Run Code Online (Sandbox Code Playgroud)
Bre*_*ast 16
来到这里是因为我刚刚遇到了这个问题,在我意识到我做错了什么之前我花了一些时间进行挖掘 - 我只是没有注意我是如何编写我的功能组件的。
我想我会在这里留下一个答案,以防有人来看,他们犯了和我一样的简单错误。
我是这样做的:
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>);
};
Run Code Online (Sandbox Code Playgroud)
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>);
};
Run Code Online (Sandbox Code Playgroud)
简单而愚蠢的错误,但花了一段时间才意识到它,所以希望这可以帮助其他人解决这个问题。
Tam*_*jid 12
我通过从 register components render 方法中删除 dispatch 到 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>
);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
使用 React 和 Material UI (MUI),我将代码更改为:
<IconButton onClick={setOpenDeleteDialog(false)}>
<Close />
</IconButton>
Run Code Online (Sandbox Code Playgroud)
到:
<IconButton onClick={() => setOpenDeleteDialog(false)}>
<Close />
</IconButton>
Run Code Online (Sandbox Code Playgroud)
简单修复
小智 5
如果您使用React Navigation并且正在使用setParams或setOptions您必须将这些放在componentDidMount()类组件的方法内部或useEffects()功能组件的钩子中。