如何解决反应警告:在现有状态转换期间例如在`render`中无法更新
我有ResetPassword
组件,它呈现了Timer
组件,下面是它们的代码-
ResendPassword.js
class ResetPassword extends Component{
constructor(props){
super(props);
this.state = {
resendActive: false
};
}
endHandler(){
this.setState({
resendActive: true
})
}
render(){
return (
<Timer sec={5} counter={this.state.counter} end={this.endHandler.bind(this)}/>
)
}
}
Timer.js
const Timer = (props) => {
const [sec,setSec] = useState(props.sec);
useEffect(() => {
setSec(props.sec);
const intr = setInterval(() => {
setSec((s) => {
if(s > 0)
return --s;
props.end(); // Line: causing warning
clearInterval(intr);
return s;
});
},1000)
return () => {
clearInterval(intr);
}
},[props.counter])
return (
<span>{sec > 60 ? `${Math.floor(sec/60)}:${sec - Math.floor(sec/60)}`: `${sec}`} sec</span>
)
}
在上面的代码中,我在ResetPassword中使用计时器,并且我希望在计时器结束时进行函数调用,所以我在Endpoint组件中将endHandler作为结束传递,但调用了该函数,给出了警告-Cannot update during an existing state transition (such as within 'render')
,任何人都可以让我知道我在这里做错了吗?
预先感谢
解决方法
问题
setSec
是状态更新功能,您可以使用功能状态更新变体。此更新函数回调必须是纯函数,即具有零副作用。 props.end()
的调用是有副作用的。
解决方案
将props.end
的副作用调用拆分到其自己的效果挂钩中,使其独立于状态更新器功能。
const Timer = (props) => {
const [sec,setSec] = useState(props.sec);
useEffect(() => {
setSec(props.sec);
const intr = setInterval(() => {
setSec((s) => {
if (s > 0) return --s;
clearInterval(intr);
return s;
});
},1000);
return () => {
clearInterval(intr);
};
},[props.counter]);
useEffect(() => {
console.log(sec);
if (sec <= 0) props.end(); // <-- move invoking `end` to own effect
},[sec]);
return (
<span>
{sec > 60
? `${Math.floor(sec / 60)}:${sec - Math.floor(sec / 60)}`
: `${sec}`}{" "}
sec
</span>
);
};
建议
创建一个useInterval
钩子
const useInterval = (callback,delay) => {
const savedCallback = useRef(null);
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
const id = setInterval(savedCallback.current,delay);
return () => clearInterval(id);
},[delay]);
};
更新Timer
以使用间隔挂钩
const Timer = ({ end,sec: secProp}) => {
const [sec,setSec] = useState(secProp);
// Only decrement sec if sec !== 0
useInterval(() => setSec((s) => s - (s ? 1 : 0)),1000);
useEffect(() => {
!sec && end(); // sec === 0,end!
},[sec,end]);
return (
<span>
{sec > 60
? `${Math.floor(sec / 60)}:${sec - Math.floor(sec / 60)}`
: `${sec}`}{" "}
sec
</span>
);
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。