vue父组件更新值后,子组件无法及时更新
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue

·
发现问题:当父组件传值给子组件后,子组件通过赋值给另一个变量后,再使用这个值,这便会造成父组件更新值后,子组件无法更新的这个问题。
解决问题:可以使用watch、v-if、计算属性、provide/inject这几个方案解决
说明:此处用的是vue3做演示,但是下面演示的这些方法,在vue2同样适用(除provide/inject外)
演示
watch方案
父组件:
<template>
<button @click="check">修改</button>
<h3>父:{{ tableData }}</h3>
<test2 :va="tableData"/>
</template>
<script>
import {ref} from 'vue'
import test2 from './test2'
export default {
name: 'App',
components: {test2},
setup() {
const tableData = ref('22222')
function check() {
tableData.value = 'wwww'
}
return {check, tableData}
}
}
</script>
子组件:
<template>
<h3>子直接使用{{ va }}</h3>
<h3>子赋值后使用{{ rea.a }}</h3>
</template>
<script>
import {reactive, watch} from 'vue'
export default {
props: ['va'],
setup(props) {
const rea = reactive({a: 0})
watch(() => props.va, (newValue) => {
rea.a = newValue
},{immediate: true })
return {rea}
}
}
</script>
使用watch监听方法对于新手比较友好,也是最容易想到的。但是watch绝对不是最优解,使用watch甚至会造成代码后期维护困难以及可读性差的问题,但是目前来看,大部分人使用的仍是watch方法
v-if
父组件:
<template>
<button @click="check">修改</button>
<h3>父:{{ tableData }}</h3>
<test2 v-if="isshow" :va="tableData"/>
</template>
<script>
import {ref,nextTick} from 'vue'
import test2 from './test2'
export default {
name: 'App',
components: {test2},
setup() {
const tableData = ref('22222')
const isshow=ref(true)
function check() {
tableData.value = 'wwww'
isshow.value=false
nextTick(()=>{
isshow.value=true
})
}
return {check,isshow, tableData}
}
}
</script>
子组件:
<template>
<h3>子直接使用{{ va }}</h3>
<h3>子赋值后使用{{ rea.a }}</h3>
</template>
<script>
import {reactive} from 'vue'
export default {
props: ['va'],
setup(props) {
const rea = reactive({a: props.va})
function dd() {
console.log('qwe')
rea.a = props.va
}
dd()
return {rea,}
}
}
</script>
使用v-if也可以解决该问题,即当值修改后,配合nextTick,让子组件重新渲染(这有点类似于react的方法),这样虽然可以解决问题,但是我认为这个不太好,首先增加了不必要的代码量,其次无端的渲染组件,这会造成性能的损耗。
使用计算属性(个人认为这应该是最优解)
父组件:
<template>
<button @click="check">修改</button>
<h3>父:{{ tableData }}</h3>
<test2 :va="tableData"/>
</template>
<script>
import {ref} from 'vue'
import test2 from './test2'
export default {
name: 'App',
components: {test2},
setup() {
const tableData = ref('22222')
function check() {
tableData.value = 'wwww'
}
return {check, tableData}
}
}
</script>
子组件:
<template>
<h3>子直接使用{{ va }}</h3>
<h3>子赋值后使用{{ computedVa }}</h3>
</template>
<script>
import {computed} from 'vue'
export default {
props: ['va'],
setup(props) {
const computedVa = computed(() => props.va )
return {computedVa}
}
}
</script>
使用计算属性代码简单清晰,由于 计算属性 是基于依赖项的响应式数据计算得到的,所以它在性能方面也很高效,个人认为这是最佳方案
使用 provide/inject(该方法为vue3新增的,vue2不支持)
父组件:
<template>
<button @click="check">修改</button>
<h3>父:{{ tableData }}</h3>
<test2/>
</template>
<script>
import {ref, provide} from 'vue'
import test2 from './test2'
export default {
name: 'App',
components: {test2},
setup() {
const tableData = ref('22222')
function check() {
tableData.value = 'wwww'
}
provide('getTableData', () => tableData.value)
return {check, tableData}
}
}
</script>
子组件:
<template>
<h3>子赋值后使用{{ injectedTableData() }}</h3>
</template>
<script>
import {inject} from 'vue'
export default {
setup() {
const injectedTableData = inject('getTableData')
return {injectedTableData}
}
}
</script>
该方法在父组件中使用provide传递一个函数的方法,这样便很好的解决这个问题了
使用toRef(该方法为vue3新增的,vue2不支持)
父组件:
<template>
<button @click="updateData">更新数据</button>
<child :data="data" />
</template>
<script>
import { reactive} from 'vue'
import Child from './test2.vue'
export default {
components: { Child },
setup() {
const data = reactive({ count: 0 })
function updateData() {
data.count++
}
return { data, updateData }
},
}
</script>
子组件:
<template>
<div>
<h3>{{ data.count }}</h3>
</div>
</template>
<script>
import { toRefs } from 'vue'
export default {
props: ['data'],
setup(props) {
const data = toRefs(props.data)
return { data }
},
}
</script>
这个方法实现起来很简单,但只能在vue3中使用




vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:6 个月前 )
9e887079
[skip ci] 5 个月前
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 8 个月前
更多推荐
所有评论(0)