useEffect的退货到底如何工作?为什么要像这样执行代码?

时间:2019-12-18 01:22:13

标签: settimeout react-hooks use-effect

我正在练习react钩子,并且正在创建一个非常简单的秒表应用。当前,我的代码正在完全按照我想要的去做,但是我不明白为什么会起作用。当我点击开始时,setTimeouts运行并不断更新时间状态。当我按下停止按钮时,它将清除超时。当我没有明确告知超时时,为什么清除超时。另外,根据react docs,仅当组件卸载时,useEffect中的return才会运行。但是,我将console.logs放入其中,发现每次调用useEffect时,它都会运行返回的回调。最后,我删除了返回的回调,发现当我按下Stop时,它实际上并没有清除超时。有人可以帮我剖析吗?

import React, {useState, useEffect} from 'react';

function Stopwatch(){

  const [time, setTime] = useState(0);
  const [start, setStart] = useState(false);

  useEffect(() => {
    let timeout;
    if (start) {
      timeout = setTimeout(() => {setTime(currTime => currTime + 1);}, 1000);
    }

    return () => {
      clearTimeout(timeout);
    }
  });

  return(
    <>
      <div>{time}</div>
      <button onClick={() => setStart(currStart => !currStart)}>{start ? "Stop" : "Start"}</button>
    </>
  )
}

export default Stopwatch

1 个答案:

答案 0 :(得分:0)

当我没有明确告诉它时为什么清除超时?

在您的实现useEffect中,由于未指定依赖项数组,因此在运行useEffect后运行,因此,如果启动计时器,然后在中间按下Stop键,则清理功能将运行,并且最后的超时将被清除

它是这样的,

组件挂载-> useEffect回调将触发并返回一个函数->当组件重新渲染时,将执行返回的函数,并且循环返回到运行useEffect回调。

您可能在文档中看到的内容有一个空的依赖项数组,这是useEffect(() => { console.log('will only run when the component mounts for the first time') return () => { console.log('will only run when the component unmounts') } }, []) // nothing inside the dependencies array, run this once 的第二个参数

function Stopwatch(){
  const [time, setTime] = useState(0)
  const [start, setStart] = useState(false)

  useEffect(() => {
    // when start is false there is no reason to set up a timer or return a
    // cleanup function so lets just exit early
    if (!start) return 

    // start is true, set up the interval
    const intervalId = setInterval(() => setTime(prevTime => prevTime + 1), 1000)
    // return a cleanup function that will run only when start changes
    // to false
    return () => clearInterval(intervalId)
  }, [start]) // run this effect only when start changes

  const toggleStart = () => setStart(prevStart => !prevStart)

  return(
    <>
      <div>{time}</div>
      <button onClick={toggleStart}>{start ? "Stop" : "Start"}</button>
    </>
  )
}

这样更好地实现组件


export interface RestCriteria {
    page: number,
    pageSize: number
}

export interface ResponseMetaData {
    page: number,
    pageSize: number,
    totalRecords: number
}

export interface QueryResponse {
    metaData: ResponseMetaData,
    records: []
}

export interface RestService {

    query: (criteria: RestCriteria) => QueryResponse,

}

class Rest implements RestService
{
    query: (criteria: RestCriteria)  => { //why is this not valid??
        return {
            metaData: {
                page: 1,
                pageSize: 1,
                totalRecords: 1
            },
            records: []
        }
    };
}

export default Rest;