How to access a property or a method of alpine.js parent component from a child component?

£可爱£侵袭症+ 提交于 2020-12-31 10:54:35

问题


This is kind of an example scenario what the problem looks like,

<div x-data="{ count : 0 }">
    <div x-data>
        <span x-text="count"></span>
        <button x-on:click="count++">Increment</button>
        <button x-on:click="count--">Decrement</button>         
    </div>
</div>

It would be able to increase/decrease the data count from the child component. I thought of handling it through dispatching custom events using $dispatch() but then again in terms of design, I might need to write listeners on both parent and child component which make the logic more complex since it should be reactive as well.

There was a Github issue, and none of the proposed solutions was working.


回答1:


I thought of handling it through dispatching custom events using $dispatch() but then again in terms of design, I might need to write listeners on both parent and child component which make the logic more complex since it should be reactive as well.

This is the crux of the issue, in order to do parent-child and child-parent communication you'll need to use events. In the case of child -> parent, you'll trigger increment and decrement events (which will be listened to in the parent component using x-on:increment and x-on:decrement). In the case of parent -> child, you'll need to use $watch to trigger updates whenever count updates (I'll used the new-count event name), this will be listened to on the window from the child component using x-on:new-count.window.

Here's the full working solution (see it as a CodePen):

<div
  x-data="{ count : 0 }"
  x-init="$watch('count', val => $dispatch('new-count', val))"
  x-on:increment="count++"
  x-on:decrement="count--"
>
  <div>In root component: <span x-text="count"></span></div>
  <div
    x-data="{ count: 0 }"
    x-on:new-count.window="count = $event.detail"
  >
    <div>In nested component <span x-text="count"></span></div>
    <button x-on:click="$dispatch('increment')">Increment</button>
    <button x-on:click="$dispatch('decrement')">Decrement</button>
  </div>
</div>

In the case you've presented, the count state might be better served by using a global store that integrates with Alpine.js such as Spruce, in which case we'll read and update a shared global store to which both the parent and child components are subscribed (see the Spruce docs). You can find the working example in the following CodePen.

<div x-data x-subscribe="count">
  <div>In root component: <span x-text="$store.count"></span></div>
  <div x-data x-subscribe="count">
    <div>In nested component <span x-text="$store.count"></span></div>
    <button x-on:click="$store.count ++">Increment</button>
    <button x-on:click="$store.count--">Decrement</button>
  </div>
</div>
<script>
  Spruce.store('count', 0);
</script>

The final solution that should be mentioned is that removing the nested component would mean that the count increment and decrement would work as expected. Obviously this example was probably simplified & meant to be illustrative, so this solution might not work in a lot of cases. Note: the only difference is removing the second x-data.

<div x-data="{ count : 0 }">
    <div>
        <span x-text="count"></span>
        <button x-on:click="count++">Increment</button>
        <button x-on:click="count--">Decrement</button>         
    </div>
</div>


来源:https://stackoverflow.com/questions/62612231/how-to-access-a-property-or-a-method-of-alpine-js-parent-component-from-a-child

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!