Vuex getter中的JSON对象副本

Gre*_*ett 5 javascript vue.js

我在Vuex getter中发现了JSON的一些奇怪行为:看来这是导致按引用传递类型的问题的原因。对于上下文-我正在开发一个音乐应用程序,它将具有多个“场景”,每个场景都包含“曲目”的集合(类似于Ableton Live)。

这是我的吸气剂:

  newTrack: state => {
    let newTrack = JSON.parse(JSON.stringify(state.newTrackDefaults))
    return newTrack
  },
Run Code Online (Sandbox Code Playgroud)

这是它所指的对象:

  newTrackDefaults: {
    tune: [],
    // and other properties
  },
Run Code Online (Sandbox Code Playgroud)

然后由一个动作调用它:

  setUpNewScene: context => {
    let newScene = JSON.parse(JSON.stringify(context.state.newSceneDefaults))
    let newTrack = context.getters.newTrack  
    console.log(newTrack) // this reveals that the problem is from the getter 
    newScene.tracks.push(newTrack)
    context.commit('addNewScene', newScene)
 }
Run Code Online (Sandbox Code Playgroud)

因此,此代码的问题是,当我在第一个场景的轨道上添加项目(音高参考),然后添加新场景时,场景会自动接收与第一个场景相同的轨道。这反映在Vuex状态中(根据DevTool),而不仅仅是渲染。而且,当用户更新第一场景上的轨道时,新场景上的轨道相应地改变。因此,本能地感觉就像是按引用传递类型的错误。

通过各种console.log实验,我发现吸气剂正在返回“填充”轨迹。通过跳过getter并将操作编写为:

  setUpNewScene: context => {
    let newScene = JSON.parse(JSON.stringify(context.state.newSceneDefaults))
    let newTrack =  JSON.parse(JSON.stringify(context.state.newTrackDefaults))
    console.log(newTrack) // this works fine
    newScene.tracks.push(newTrack)
    context.commit('addNewScene', newScene)
 }
Run Code Online (Sandbox Code Playgroud)

...尽管我有个解决办法,但我对最初的行为感到困惑。吸气剂会干扰JSON功能吗?还是可能导致这种情况的其他原因?

Eri*_*uan 5

Vuex getter被缓存。

https://vuex.vuejs.org/en/getters.html

像计算的属性一样,getter的结果将基于其依赖项进行缓存,并且仅在其某些依赖项发生更改时才重新评估。

如果其依存关系不变,则获取器将返回其最后返回的值。大概你不是在变异newTrackDefaults。这意味着吸气剂newTrack将永远不会更新。这意味着context.getters.newTrack每次都返回相同的对象。因此,您认为自己正在创建的所有“新”轨道实际上都是相同的轨道。

当处理默认值时,我喜欢创建一个返回默认值的函数。然后,我可以随时随地调用该函数,而无需进行任何时髦的缓存业务。

function newTrackDefaults() {
    return {
        tune:[],
        // and other properties
    }
}


setUpNewScene: context => {
    let newScene = JSON.parse(JSON.stringify(context.state.newSceneDefaults))
    let newTrack = newTrackDefaults() 
    newScene.tracks.push(newTrack)
    context.commit('addNewScene', newScene)
 }
Run Code Online (Sandbox Code Playgroud)

有趣的事实:吸气剂可以返回函数,因此您也可以像这样修复它。

newTrack: state => () => {
    let newTrack = JSON.parse(JSON.stringify(state.newTrackDefaults))
    return newTrack
  },
Run Code Online (Sandbox Code Playgroud)

现在您需要调用getter,因为它现在是一个函数。

let newTrack = context.getters.newTrack()
Run Code Online (Sandbox Code Playgroud)