Javascript 如何使用useState在react功能组件的循环中正确设置状态

Javascript 如何使用useState在react功能组件的循环中正确设置状态,javascript,reactjs,closures,react-hooks,Javascript,Reactjs,Closures,React Hooks,假设我正在上传一堆文件,并试图跟踪正在进行的文件,这样每当上传完成时,我都会减少我的状态,直到所有文件都完成,最后我将上传状态更改为false: (这里我做了一个sleep函数来模拟上传过程) import React,{useState}来自“React”; 常量睡眠=(ms,dev=1)=>{ 常量msWithDev=(Math.random()*dev+1)*ms 返回新承诺(resolve=>setTimeout(resolve,msWithDev)) } 函数计数器(){ 常量[,se

假设我正在上传一堆文件,并试图跟踪正在进行的文件,这样每当上传完成时,我都会减少我的状态,直到所有文件都完成,最后我将上传状态更改为
false
: (这里我做了一个
sleep
函数来模拟上传过程)

import React,{useState}来自“React”;
常量睡眠=(ms,dev=1)=>{
常量msWithDev=(Math.random()*dev+1)*ms
返回新承诺(resolve=>setTimeout(resolve,msWithDev))
}
函数计数器(){
常量[,setSortEnabled]=使用状态(true)
const[count,setCount]=useState(0)
常数arr=[1,2,3,4,5]
const upload=async()=>{
等待睡眠(1000)
设置计数(c=>c-1)
log(`count state:${count}`)
如果(计数==0){
console.warn('再次将排序设置为启用')
setSortEnabled(真)
}
}
const onClick=()=>{
console.warn('排序设置为禁用')
arr.forEach(项目=>{
设置计数(c=>c+1)
控制台错误(计数)
上传()
})
}
返回(
点击我!
);
}
导出默认计数器;
问题在于
上传

function `console.log(\`count state: ${count}\`)`
始终记录
0
,这意味着状态从未更新过

我做错了什么

这意味着状态从未更新过

它确实得到更新,您只是记录了过时的值

闭包是捆绑在一起(封闭)的函数与其周围状态(词汇环境)的引用的组合。换句话说,闭包允许您从内部函数访问外部函数的作用域

要修复它,请使用
setState

这意味着状态从未更新过

它确实得到更新,您只是记录了过时的值

闭包是捆绑在一起(封闭)的函数与其周围状态(词汇环境)的引用的组合。换句话说,闭包允许您从内部函数访问外部函数的作用域

要修复它,请使用
setState


您必须使用
Promise.all
等待上传所有文件,而不是依赖计数。在您的情况下,count是从closure接收的,因此即使状态被更新,count变量也不会受到影响

您可以使用Promise.all like实现上述逻辑

function Counter() {
  const [, setSortEnabled] = useState(true)
  const arr = [1, 2, 3, 4, 5]

  const upload = async () => {
    await sleep(1000);
  }


  const onClick = async ()  => {
    console.warn('Sort set to disabled.')
      const promises = arr.map(item => {
        console.error(count)
        return upload()
      });
      await Promise.all(promises);
      console.warn('Sort set to enabled again.')
      setSortEnabled(true)
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;
函数计数器(){
常量[,setSortEnabled]=使用状态(true)
常数arr=[1,2,3,4,5]
const upload=async()=>{
等待睡眠(1000);
}
const onClick=async()=>{
console.warn('排序设置为禁用')
const promises=arr.map(项=>{
控制台错误(计数)
返回上载()
});
等待承诺。所有(承诺);
console.warn('再次将排序设置为启用')
setSortEnabled(真)
}
返回(
点击我!
);
}
导出默认计数器;
更新:

要绕过计数状态的闭包问题,可以使用refs和useffect。但是,这是一种变通方法,不应被优先考虑

import React, { useState} from "react";

const sleep = (ms, dev =1 ) => {
  const msWithDev = (Math.random() * dev + 1) * ms
  return new Promise(resolve => setTimeout(resolve, msWithDev))
}

function Counter() {
  const [, setSortEnabled] = useState(true)
  const [count, setCount] = useState(0)
  const arr = [1, 2, 3, 4, 5]
  const countRef = useRef(count);
  useEffect(() => {
     countRef.current = count;
  }, [count ]);
  const upload = async () => {
    await sleep(1000)
    setCount(c => c - 1)

      console.log(`count state: ${count}`)

      if (countRef.current === 0) {
        console.warn('Sort set to enabled again.')
        setSortEnabled(true)
    }
  }


  const onClick = ()  => {
    console.warn('Sort set to disabled.')
      arr.forEach(item => {
        setCount(c => c + 1)
        upload();
      })
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;
import React,{useState}来自“React”;
常量睡眠=(ms,dev=1)=>{
常量msWithDev=(Math.random()*dev+1)*ms
返回新承诺(resolve=>setTimeout(resolve,msWithDev))
}
函数计数器(){
常量[,setSortEnabled]=使用状态(true)
const[count,setCount]=useState(0)
常数arr=[1,2,3,4,5]
const countRef=useRef(计数);
useffect(()=>{
countRef.current=计数;
},[计数];
const upload=async()=>{
等待睡眠(1000)
设置计数(c=>c-1)
log(`count state:${count}`)
如果(countRef.current==0){
console.warn('再次将排序设置为启用')
setSortEnabled(真)
}
}
const onClick=()=>{
console.warn('排序设置为禁用')
arr.forEach(项目=>{
设置计数(c=>c+1)
上传();
})
}
返回(
点击我!
);
}
导出默认计数器;

您必须使用
Promise.all
等待上传所有文件,而不是依赖计数。在您的情况下,count是从closure接收的,因此即使状态被更新,count变量也不会受到影响

您可以使用Promise.all like实现上述逻辑

function Counter() {
  const [, setSortEnabled] = useState(true)
  const arr = [1, 2, 3, 4, 5]

  const upload = async () => {
    await sleep(1000);
  }


  const onClick = async ()  => {
    console.warn('Sort set to disabled.')
      const promises = arr.map(item => {
        console.error(count)
        return upload()
      });
      await Promise.all(promises);
      console.warn('Sort set to enabled again.')
      setSortEnabled(true)
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;
函数计数器(){
常量[,setSortEnabled]=使用状态(true)
常数arr=[1,2,3,4,5]
const upload=async()=>{
等待睡眠(1000);
}
const onClick=async()=>{
console.warn('排序设置为禁用')
const promises=arr.map(项=>{
控制台错误(计数)
返回上载()
});
等待承诺。所有(承诺);
console.warn('再次将排序设置为启用')
setSortEnabled(真)
}
返回(
点击我!
);
}
导出默认计数器;
更新:

要绕过计数状态的闭包问题,可以使用refs和useffect。但是,这是一种变通方法,不应被优先考虑

import React, { useState} from "react";

const sleep = (ms, dev =1 ) => {
  const msWithDev = (Math.random() * dev + 1) * ms
  return new Promise(resolve => setTimeout(resolve, msWithDev))
}

function Counter() {
  const [, setSortEnabled] = useState(true)
  const [count, setCount] = useState(0)
  const arr = [1, 2, 3, 4, 5]
  const countRef = useRef(count);
  useEffect(() => {
     countRef.current = count;
  }, [count ]);
  const upload = async () => {
    await sleep(1000)
    setCount(c => c - 1)

      console.log(`count state: ${count}`)

      if (countRef.current === 0) {
        console.warn('Sort set to enabled again.')
        setSortEnabled(true)
    }
  }


  const onClick = ()  => {
    console.warn('Sort set to disabled.')
      arr.forEach(item => {
        setCount(c => c + 1)
        upload();
      })
    }

  return (
    <>
    <button onClick={onClick}>Click me!</button>
    </>
  );
}

export default Counter;
import React,{useState}来自“React”;
常量睡眠=(ms,dev=1)=>{
常量msWithDev=(Math.random()*dev+1)*ms
返回新承诺(resolve=>setTimeout(resolve,msWithDev))
}
函数计数器(){
常量[,setSortEnabled]=使用状态(true)
const[count,setCount]=useState(0)
常数arr=[1,2,3,4,5]
const countRef=useRef(计数);
useffect(()=>{
countRef.current=计数;
},[计数];
const upload=async()=>{
等待睡眠(1000)
设置计数(c=>c-1)
log(`count state:${count}`)
如果(countRef.current==0){
console.warn('再次将排序设置为启用')
setSortEnabled(真)
}
}
const onClick=()=>{
console.warn('排序设置为禁用')
arr.forEach(项目=>{
设置计数(c=>c+1)
上传();