Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么分拣会立即完成?_Javascript_Reactjs - Fatal编程技术网

Javascript 为什么分拣会立即完成?

Javascript 为什么分拣会立即完成?,javascript,reactjs,Javascript,Reactjs,我一直在尝试使用react显示数组排序过程的每个步骤。 我已经实现了冒泡排序算法,但我注意到一件非常奇怪的事情: 当我使用这种方法时,UI会立即显示排序的数组: function BubbleSort({ array }) { const [elements, setElements] = useState(array); const onSort = () => { console.log('onSort fired') const length = eleme

我一直在尝试使用react显示数组排序过程的每个步骤。 我已经实现了冒泡排序算法,但我注意到一件非常奇怪的事情:

当我使用这种方法时,UI会立即显示排序的数组:

function BubbleSort({ array }) {
  const [elements, setElements] = useState(array);

  const onSort = () => {
    console.log('onSort fired')
    const length = elements.length;
    const newElements = elements.slice();

    let swap = 0;

    for (let i = 0; i < length; i++) {
      for (let j = i + 1; j < length; j++) {
        if (newElements[i].value > newElements[j].value) {
          console.log('Swap fired', swap);

          const buffer = newElements[i];
          newElements[i] = newElements[j];
          newElements[j] = buffer;

          swap++
          
          setTimeout(() => setElements(newElements.slice()), 1000 * swap);

        }
      }
    }
  }

  return (
    <ArrayView elements={elements} onSort={onSort}/>
  );
}
函数BubbleSort({array}){
const[elements,setElements]=useState(数组);
常量onSort=()=>{
console.log('onSort-fired')
常量长度=elements.length;
const newElements=elements.slice();
设swap=0;
for(设i=0;inewElements[j].value){
log('Swap-fired',Swap);
常量缓冲区=新元素[i];
新元素[i]=新元素[j];
新元素[j]=缓冲区;
交换++
setTimeout(()=>setElements(newElements.slice()),1000*swap);
}
}
}
}
返回(

设置超时
是非阻塞的

在第一个代码示例中,您在排序过程的每个步骤后都设置了一个超时。但是,这并不会导致代码暂停和等待,而是会安排回调在以后发生。因此,您的代码将继续并执行排序的下一步,然后安排另一个回调,依此类推。经过1秒后,回调将触发,但数组已完成排序,因此UI将更改为完全排序的数组

在第二个示例中,您存储了步骤并将超时间隔适当地触发。回调不查看数组的全局状态,而是查看每个事件并按预期播放它们

编辑:处理您的评论

调用
slice
会创建数组的副本,这是正确的。问题是您在调度回调后调用
slice

创建arrow函数时,会捕获其作用域中的变量,但在调用函数之前不会计算其中的代码。在这种情况下,1秒后,它将调用
newElements.slice()
并将其传递给
setElements
。此时,
newElements
已被排序,所有副本看起来都一样

你可以用两种方法来解决这个问题。第一种方法是按照你在评论中提到的去做。我个人觉得这很难理解。另一种方法是立即调用
slice
,并在回调中使用该值

const newElementsCopy = newElements.slice();
setTimeout(() => setElements(newElementsCopy), 1000 * swap);

当计时器在第一秒内等待触发时,循环结束。当计时器功能运行时(第一次),
newElements
是完全排序的。如果我在使用
slice
函数时理解正确,它会创建数组的新副本。因此,在每一步中,我都会在timer函数中传递一个新数组。谢谢,我得到了它!我只需要将数组的副本传给回调,如下所示:
setTimeout((copyOfArray)=>setElements(copyOfArray),1000*swap,copyOfArray)
@RomanAndreev更新了我的答案,以更明确地解决这个问题。在重新阅读您的问题和我的编辑后,我意识到我的初始答案有点偏离了基准。问题与调用
切片的位置有关,而不是
设置超时。
const newElementsCopy = newElements.slice();
setTimeout(() => setElements(newElementsCopy), 1000 * swap);