简体   繁体   中英

What's the correct way to dispatch/forward events across nested in components in Svelte?

I'm curious, what's the best way to forward or dispatch events across multiple levels in component tree in Svelte JS?

Say I have App.Svelte, some intermediate number levels, each containing a child component, and Modal.Svelte. If I want to forward or dispatch an event from Modal to App, what's the right way to do this?

As I understand it, event forwarding in Svelte will traverse up the component tree and forward the event to the first parent that references the forwarded event. (Is this the correct interpretation?)

And using event dispatch approach, each nested component would need to 1/ import createEventDispatcher, 2/ create a dispatcher variable, 3/ define a function, which dispatches the event. Then parent's would need to import the function and reference it inside a tag, such as <p> . (Is this correct?)

If I'm correct on both of the above, I'm wondering if there isn't a more streamlined approach, eg connecting the event to stores, which would effectively flatten the component tree such that any component could receive the forwarded event. Though I imagine that this could induce some hard to debug behavior if multiple components reference the same forwarded event.

To forward a event from a child component or DOM element to the parent, you just have to define an on:event without handler. Eg

<button on:click >
<Component on:open >

No need to use createEventDispatcher just for forwarding.

If you want to share events more widely, you can create an EventTarget and send events through that. Since subscriptions would not happen in the template via on:event , you have to make sure to remove listeners again. You can also use a context to just expose the object to a sub-tree of the component hierarchy.

Alternatively, events can be dispatched directly to DOM elements, such events will bubble up the entire element hierarchy (if enabled in the event options).

someElement.dispatchEvent(
  new CustomEvent('my-event', { bubbles: true })
);

If you dispatch events to the window , directly or via bubbling, you can subscribe to those more conveniently using svelte:window :

<svelte:window on:my-event={() => ...} />

(These handlers are removed automatically when the component is destroyed.)

You might consider instead using accessor functions. In App.svelte, define a function that manipulates your top-level variables. Then place that function in an accessor object and pass that down as a prop to all your components that may need it.

<script>
[App.svelte]

let myVar, myObj, myWhatever

function updateMyVal(newValue) {
  myVar = newValue
}

function mergeMyObject(mergeObj) {
  myObj = {...myObj, ...mergeObj}
}

let accessorObject = {
  updateMyVal: updateMyVal,
  mergeMyObject: mergeMyObject
}

</script>

<ChildComponent {accessorObject} {myVar} {myObj} />



. . .
[ChildComponent.svelte]
<script>
  export let accessorObject, myVar, myObj

  accessorObject.updateMyVal(1234)

  accessorObject.mergeMyObject({newProp: newVal})
</script>

And so forth... this has the advantage of pushing changes to application-wide variables from the top down, which I've found to work better for complex SPAs than a web of events, two-way-bindings or stores, at least in my limited experience.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM