在 Vue.js 中将数据沿链向上传递的解决方案真的是链事件侦听器/发射器吗?

2022-01-25 00:00:00 javascript vue.js vue-component

Vue API 文档/指南讨论了父母将道具传递给孩子的模式,孩子们通过事件与父母交流.此外,该指南强调,孩子绝对不应该改变父母的数据,因为这是父母的责任.

对于大多数扁平结构,您有一个父级(例如应用程序")并且所有组件都是该父级的子级,这可以正常工作;任何事件只需要冒泡一次.

但是,如果您正在编写一个划分的结构(例如,应用程序(保持状态)-> ActiveComponent -> FormGroup -> Inputs...),那么在更深的部分(如 FormGroup/Inputs)中构建交互需要每个连接上的事件链.输入需要做一个事件 v-on:keyup.enter="addInputValue";那么 FormGroup 需要有一个 v-on:addInputValue="bubbleInputValue";ActiveComponent 需要一个 v-on:bubbleInputValue="bubbleInputValue";最后 App 需要响应 bubbleInputValue.

链中的每个环节都需要知道如何负责处理 App 想要从 Input<的最深分支了解的事件的冒泡,这似乎真的很荒谬/代码>.Vue 指南建议使用 State Store 模式来处理这个问题——但这实际上并没有解决链接问题(因为您只是添加了一个不同的根;Store).

是否有一个公认的约定/模式来解决遍历组件树的通信困难?

解决方案

如果你真的想将状态保持在 app 级别,可以使用

The Vue API Docs/Guide talk about the pattern of parents passing props to children, who communicate back up to their parents via events. Additionally, the guide stresses that children absolutely should not mutate parent data, as that is the responsibility of the parent.

For a mostly-flat structure where you have one parent (e.g. 'App') and all components are children of that one parent, this works okay; any event only has to bubble once.

However, if you are composing a structure that is compartmentalized (e.g. App (holds state) -> ActiveComponent -> FormGroup -> Inputs...) then building interaction within the deeper parts (like the FormGroup/Inputs) requires making an event chain on each connection. Input will need to make an event v-on:keyup.enter="addInputValue"; then FormGroup will need to have a v-on:addInputValue="bubbleInputValue"; ActiveComponent will need a v-on:bubbleInputValue="bubbleInputValue"; and finally the App will need to respond to bubbleInputValue.

This seems really absurd that every link in the chain needs to know how to be responsible for handling the bubbling of an event that App wants to know about from the deepest branch of Input. The Vue guide suggests a State Store pattern to deal with this -- but that doesn't actually address the chaining (as you're simply adding a different root; the Store).

Is there an accepted convention/pattern for addressing the difficulty of communication that traverses a tall tree of components?

解决方案

If you really want to keep state at app level, you can use non parent child communication

Which will be like following:

var bus = new Vue()
----------------------------
// in component A's method
bus.$emit('id-selected', 1)
----------------------------
// in component B's created hook
bus.$on('id-selected', function (id) {
  // ...
})

But as stated in documentation:

In more complex cases, you should consider employing a dedicated state-management pattern.

Vuex to the rescue

As suggested in the comments, the general practice in the community for centralise state management is vuex, so all your state is separated from your component and view, you have actions which changes the store, which reactively changes your view. Flow look like this:

相关文章