React setState 钩子不适用于 useEffect

fju*_*urr 2 javascript reactjs

我有以下代码。这个想法是为模拟组件创建一个简单的加载

const [loading, setLoading] = useState(false)

  function mockLoading () {
    setLoading(true)
    console.log('1', loading)
    setTimeout(() => {
      setLoading(false)
      console.log('2', loading)
    }, 3000)
  }

  useEffect(() => {
    mockLoading()
  }, []);
Run Code Online (Sandbox Code Playgroud)

但由于某种原因, setLoading 不起作用。Console.log 1 和 2 都是假的

Dup*_*cas 6

声明您的handler内部useEffect并在外部登录

const [loading, setLoading] = useState(false)

  useEffect(() => {
      function mockLoading () {
         setLoading(true)
         console.log('1', loading)
         setTimeout(() => {
         setLoading(false)
         console.log('2', loading)
       }, 3000)
  }
    mockLoading()
  }, []);

  console.log(loading)
Run Code Online (Sandbox Code Playgroud)

此外,你应该清洁你timeoutunmount

useEffect(() =>{
    const timeout = setTimeout(() =>{}, 0)

    return () => clearTimeout(timeout)
},[])
Run Code Online (Sandbox Code Playgroud)


Kyl*_*yle 5

几件事。一个问题是,当您设置状态时,状态不会立即更新。所以你的第一个 console.log 会看到旧的状态。不仅如此,当你的 effect 被调用和mockLoading被调用时,它只会看到它被调用时存在的状态实例。因此,对变量的任何更改都不会被mockLoading. 这就是效果具有依赖性的原因。这样,当依赖项更新时,您就会看到它。但我不认为这里有一个依赖会帮助你的代码是如何结构的。我不是你的最终目标100%清楚,但要完成你想要根据您提交的代码,你会想什么useRef,而不是useStateuseRef为您提供一个价值始终是最新的对象。看:

const loadingRef = useRef(false)

function mockLoading () {
    loadingRef.current = true;
    console.log('1', loadingRef.current)
    setTimeout(() => {
        loadingRef.current = false;
      console.log('2', loadingRef.current)
    }, 3000)
}

useEffect(() => {
    mockLoading()
}, []);
Run Code Online (Sandbox Code Playgroud)

除非您绝对需要,否则通常不赞成使用 refs。尝试重构您的代码以依赖loading于您的useEffect调用。但请记住,如果您mockLoading总是loading在调用时更新,则最终可能会出现无限循环。loading如果尚未设置为您想要的值,请尝试仅更新。如果您的最终目标是loading在 3 秒后更新,请尝试以下操作:

const [loading,setLoading] = useState(false);

useEffect(() => {
    setTimeout(() => {
        setLoading(true);
    },3000);
},[]);

return <span>{loading ? 'Loading is true!' : 'Loading is false!'}</span>;
Run Code Online (Sandbox Code Playgroud)

如果你想在不渲染的情况下检查加载的值,那么你需要另一个useEffect依赖于loading

const [loading,setLoading] = useState(false);

useEffect(() => {
    setTimeout(() => {
        setLoading(true);
    },3000);
},[]);

useEffect(() => {
    console.log(loading);
},[loading]);

return <span>{loading ? 'Loading is true!' : 'Loading is false!'}</span>;
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。