跳转到内容

Vue 组件状态重置

刀刀
0字
0分钟
2026/8/16

场景

业务中有重置按钮,需要把用户修改的值重置为默认旧值,之前的写法:

js
const state = ref({
  a: 1,
  b: 2,
  c: [1, 2, 3],
})

const reset = () => {
  state.value = {
    a: 1,
    b: 2,
    c: [1, 2, 3],
  }
}

属性少时可以这样写,属性多时每次重置都要写一遍,维护成本高,需要优化。

ref

传入函数式

声明一个函数,接收回调函数,返回默认值,重置时重新赋值:

ts
export function useResettableRefFn<T>(cb: () => T) {
  const state = ref(cb())
  const reset = () => {
    state.value = cb()
  }
  return { state, reset }
}
ts
import { useResettableRefFn } from './index'

const { state, reset } = useResettableRefFn(() => ({
  a: 1,
  b: 2,
  c: [1, 2, 3],
}))
reset() // 重置

传入函数,重新赋值时是新对象地址,不会有内存冲突,每次都是新值。

缺点:必须传入函数,步骤繁琐。如果只想传入对象,需要修改。

传入对象式

修改为接收对象,内部通过 JSON.parseJSON.stringify 做深拷贝,避免浅拷贝修改旧值后新值也跟着变化。

深拷贝使用 JSON 方法,如果使用者对象内有 MapSet 等,则无法拷贝。为深拷贝引入 lodash 不合适,改为参数形式,用户不传则使用 JSON 方法,需要使用 cloneDeep 则自己传。

ts
function defaultClone(value: any) {
  if (value === null || typeof value !== 'object') return value
  return JSON.parse(JSON.stringify(value))
}

export function useResettableRef<T>(value: T, clone = defaultClone) {
  const initialValue = clone(value)
  const state = ref(value)
  const reset = () => {
    state.value = clone(initialValue)
  }
  return { state, reset }
}
ts
import { useResettableRef } from './index'
import { cloneDeep } from 'load-dash'

const { state, reset } = useResettableRef(
  {
    a: 1,
    b: 2,
    c: [1, 2, 3],
  },
  cloneDeep,
)
reset() // 重置

reset 中赋值也需要深拷贝。如果不深拷贝,第一次把 initialValue 赋值给 state 后,stateinitialValue 引用地址相同,修改 state 的值,initialValue 也会跟着改变,后续重置失败。

reactive

reactive 写法与 ref 类似,但 reactive 声明的响应式变量不能直接重置,否则丢失 proxy 代理,丢失响应式。使用 Object.assign() 合并对象。

Object.assign() 有一个局限:对象原有属性,新属性没有,则不做处理。例如 Object.assign(a, b)aa1a2b 只有 a1,则只覆盖 a1a2 不做处理,导致重置功能未生效。

解决:每次合并前删除原对象所有属性,避免遗留:

ts
export function useResettableReactive<T extends object>(
  value: T,
  clone = defaultClone,
) {
  const state = reactive(clone(value))
  const reset = () => {
    Object.keys(state).forEach((key) => {
      delete state[key]
    })
    Object.assign(state, clone(value))
  }
  return [state, reset] as count
}
ts
import { useResettableReactive } from './index'

const [obj, resetObj] = useResettableReactive({
  a: 1,
  b: 2,
  c: [1, 2, 3],
})

导出为数组,使用时通过数组解构自定义变量和函数名称。

动手实操

跳转预览:点击跳转

贡献者

The avatar of contributor named as duyidao duyidao
The avatar of contributor named as 刀刀 刀刀
The avatar of contributor named as v_duyilin v_duyilin

页面历史

刀刀博客累计访客 人;文档累计访问量共