javascript 这个React useReducer处理程序是一个不纯函数吗?

t9aqgxwy  于 2023-04-19  发布在  Java
关注(0)|答案(1)|浏览(113)

我在React中看到了意想不到的结果。StrictMode调用了我的useReducer函数两次-我正在交换数组中的元素,但StrictMode导致我的交换将元素跳转到两个插槽,而不是期望的一次。我不确定这段代码的“不纯”是什么?

case 'swap_section': {

   let modified_song = {...song}

   let target_section_index = modified_song.song.songsheet.aSections.findIndex(
          section => action.daw ===  section.daw
   ) 
   let target_section = modified_song.song.songsheet.aSections[target_section_index] 
   let swap_section_index = action.direction === "down" 
                 ? target_section_index + 1 :  target_section_index - 1

   // StrictMode calling this twice may attempt to swap w/ (final index + 1) - check index & undefined
        if(swap_section_index > -1 && swap_section_index < modified_sections.length) {
            let swap_section = modified_song.song.songsheet.aSections[swap_section_index]
            if(swap_section) {
                modified_song.song.songsheet.aSections[swap_section_index] = target_section
                modified_song.song.songsheet.aSections[target_section_index] = swap_section
                return modified_song
            }
        }
   return modified_song 
}
xzv2uavs

xzv2uavs1#

代码不是pure,因为外部的值song.song被修改了 (我假设“外部”是你没有显示的代码)

对象标识

你显然是想创建一个song对象的副本,但是你的方法并没有“深复制”这个对象,也就是下面这行:

let modified_song = {...song}

song的所有属性复制到modified_songmodified_song现在是与song不同的对象,但modified_song的所有属性仍然具有与song的属性相同的(相同的)值,即modified_song.songsong.song相同。
现在,当您修改modified_song.song时,您也在修改song.song(并且下一次执行代码时,输入是不同的)。

解决方案

您需要复制最后一个属性,保持原始属性不变,并仅使用副本,例如:

// -- WRONG: --
// modified_song.song.songsheet.aSections[swap_section_index] = target_section
// modified_song.song.songsheet.aSections[target_section_index] = swap_section
// return modified_song

// -- RIGHT: --
return {
    swap_section_index: target_section,
    target_section_index: swap_section
};

修改原件

直接更改modified_song.song...不是在React中应该采用的方式。
如果您认为需要将结果写回song.song...,可能有某种方法可以重构状态管理,或者您可以在某个事件中调用状态更改,......但我真的不能说,我需要更多的信息来找到特定的解决方案。

相关问题