繁体   English   中英

反应警告:在现有的 state 过渡期间无法更新(例如在“渲染”中)

[英]React Warning: Cannot update during an existing state transition (such as within `render`)

我有渲染Timer组件的ResetPassword组件,下面是它们的代码 -

重发密码.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)}/>
        )
    }
}

计时器.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>
    )
}

In Above code I'm using timer in ResetPassword and I want a function call when timer ends so I'm passing endHandler as end in Timer component but calling that function giving - Warning: Cannot update during an existing state transition (such as within 'render') ,谁能让我知道我在这里做错了什么?

提前致谢

问题

setSec是 state 更新 function 并且您使用功能 state 更新变体。 此更新 function 回调必须是纯 function,即副作用为零。 props.end()的调用是一个副作用。

解决方案

props.end的副作用调用拆分为自己的效果挂钩,使其独立于 state 更新程序 function。

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>
  );
};

编辑 react-warning-cannot-update-during-an-existing-state-transition-such-as-within 问题

建议

创建一个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>
  );
};

编辑 react-warning-cannot-update-during-an-existing-state-transition-such-as-within

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM