理解 AlpineJS 的 x-init 和 x-for

huangapple go评论113阅读模式
英文:

Understanding AlpineJS x-init and x-for

问题

以下是您的代码的翻译部分:

  1. 我有一些东西,我一直在努力解决,我已经解决了,但我不太确定原因,希望您可以帮助理解。
  2. 我的想法是创建一个控制台框,我会通过Laravel Echo接收的日志来更新它。
  3. 然后,在我的`<script>`标签中,我有以下内容:
  4. ```javascript
  5. getLogs() {
  6. Echo.channel('logs').listen('.logs', (log) => {
  7. // 根据事件名称和数据执行所需的操作
  8. console.log(log);
  9. this.logs.push(log.message.function + ': ' + log.message.task + ' - ' + log.message.status);
  10. window.dispatchEvent(new CustomEvent("scrollDown"));
  11. });
  12. }

这花了我相当长的时间才能让它工作,主要是x-for更新logs变量的新添加时遇到了问题。不过,通过将getLogs()添加到我的容器<div>x-init中,我成功解决了这个问题。

我的理解是,x-init只在元素渲染时执行。我不太明白为什么将函数放在x-init中会允许x-for正确更新。有人能提供一些见解来帮助我理解吗?

这是代码的一个简化示例:

  1. const appState = {
  2. events: [],
  3. async loadEvent(event) {
  4. // 向服务器发送请求并处理响应
  5. },
  6. async retrieveLoadedEventsTable() {
  7. // 从服务器获取数据
  8. }
  9. }
  1. <div x-data="appState" x-init="retrieveLoadedEventsTable()">
  2. <template x-for="event, index in events" :key="event.id">
  3. <!-- 渲染事件属性的HTML - 第一次加载时正常工作 -->
  4. </template>
  5. </div>
  6. <div x-data="appState" x-init="retrieveIncompleteEventsTable()">
  7. <x-button class="ml-3" x-bind:disabled="event.disabled" x-on:click="loadEvent(unloadedEvents[index])">
  8. 加载事件
  9. </x-button>
  10. <!-- 这能够将事件加载到SQL表中,但包含在具有retrieveLoadedEventsTable的div中的模板中的事件不会更新 -->
  11. </div>

请注意,以上翻译只包含代码的主要部分,不包括其他信息。如果您需要进一步的解释或帮助,请随时提出具体问题。

英文:

I have something that i've been working on which I got working but I'm not really sure why, hoping you can help understand.

The idea was to essentially have a console box which I update with logs that I receive through laravel echo.

  1. &lt;div x-data=&quot;appState&quot; class=&quot;w-10/12 m-auto&quot; x-init=&quot;getLogs()&quot; x-show=&quot;consoleShow&quot;&gt;
  2. &lt;div
  3. class=&quot;coding inverse-toggle h-60 overflow-y-scroll px-5 pt-4 shadow-lg text-gray-100 text-xs font-mono subpixel-antialiased
  4. bg-gray-800 pb-6 pt-4 rounded-lg leading-normal overflow-hidden&quot; id=&quot;consoleBox&quot;&gt;
  5. &lt;div class=&quot;top mb-2 flex flow-root static&quot;&gt;
  6. &lt;div class=&quot;h-4 w-4 bg-red-500 rounded-full float-right cursor-pointer&quot; x-on:click=&quot;consoleShow = false&quot;&gt;&lt;/div&gt;
  7. &lt;/div&gt;
  8. &lt;div class=&quot;mt-4 flex&quot;&gt;
  9. {{-- &lt;span class=&quot;text-green-400&quot;&gt;computer:~$&lt;/span&gt; --}}
  10. &lt;p class=&quot;flex-1 typing items-center pl-2&quot;&gt;
  11. &lt;template x-for=&quot;(log, index) in logs&quot; :key=&quot;index&quot;&gt;
  12. &lt;li class=&quot;list-none&quot; x-text=&quot;log&quot;&gt;&lt;/li&gt;
  13. &lt;/template&gt;
  14. &lt;br&gt;
  15. &lt;/p&gt;
  16. &lt;/div&gt;
  17. &lt;/div&gt;
  18. &lt;/div&gt;

Then I within my appState in <script> tags

  1. getLogs() {
  2. Echo.channel(&#39;logs&#39;).listen(&#39;.logs&#39;, (log) =&gt; {
  3. // do what you need to do based on the event name and data
  4. console.log(log);
  5. this.logs.push(log.message.function+&#39;: &#39;+log.message.task+&#39; - &#39;+log.message.status);
  6. window.dispatchEvent(new CustomEvent(&quot;scrollDown&quot;));
  7. });
  8. }

It took my quite a while to get working, essentially i had issues with the x-for updating with new additions to the logs var. However i managed to resolve it by adding getLogs() to the x-init of my container div.

My understanding was that the x-init was only there to execute when the element is rendered. I don't really understand why having the function in x-init would allow the x-for to update correctly. Could anyone provide some insights to help wrap my head around this?

Adding in a cutback example of the code:

  1. const appState = {
  2. events: [],
  3. async loadEvent(event) {
  4. fetch(&quot;/admin/scrapeEvent&quot;, {
  5. method: &quot;POST&quot;,
  6. headers: {
  7. &quot;Content-Type&quot;: &quot;application/json&quot;,
  8. &#39;X-CSRF-TOKEN&#39;: document.head.querySelector(&#39;meta[name=csrf-token]&#39;).content,
  9. Accept: &quot;application/json&quot;,
  10. },
  11. body: JSON.stringify(event)
  12. })
  13. .then(() =&gt; {
  14. })
  15. .catch(() =&gt; {
  16. })
  17. .finally(() =&gt; {
  18. this.retrieveLoadedEventsTable();
  19. });
  20. },
  21. async retrieveLoadedEventsTable() {
  22. try {
  23. let response = await fetch(&#39;/admin/findNewEvents/loaded&#39;);
  24. let data = await response.json();
  25. for (let item of data) item.disabled = true;
  26. this.events = data;
  27. } catch (itsTheErrorObject) {
  28. console.log(&quot;something went wrong&quot;);
  29. }
  30. }
  31. }
  32. &lt;div x-data=&quot;appState&quot; x-init=&quot;retrieveLoadedEventsTable()&quot;&gt;
  33. &lt;template x-for=&quot;event, index in events&quot; :key=&quot;event.id&quot;&gt;
  34. /** HTML that renders event.atrributes - Works fine on first load **/
  35. &lt;/template&gt;
  36. &lt;/div&gt;
  37. &lt;div x-data=&quot;appState&quot; x-init=&quot;retrieveIncompleteEventsTable()&quot;&gt;
  38. &lt;x-button class=&quot;ml-3&quot; x-bind:disabled=&quot;event.disabled&quot; x-on:click=&quot;loadEvent(unloadedEvents[index])&quot;&gt;
  39. Load Event
  40. &lt;/x-button&gt;
  41. /** This works fine to load my event into the sql table, i can confirm that it runs through and executes the finally in loadEvent, but the events in the template contained in the div with x-init with retrieveLoadedEventsTable does not update **/
  42. &lt;/div&gt;

答案1

得分: 1

我的理解是,x-init 仅用于在元素渲染时执行。

不,x-init 指令 在元素初始化阶段被调用。在这一点上,Alpine.js 已经从 x-data 中创建了数据变量,但尚未渲染任何内容(尚未修改 DOM)。x-init 是推荐的位置,用于放置一个函数,例如调用一个 API,然后附加一些在 x-data 中定义的变量,或者创建一个事件监听器,以后会更改数据,就像在你的示例中一样。

在执行 x-init 中的函数后,Alpine.js 使用实际的 logs 变量渲染组件。当你的 getLogs() 函数中的事件监听器捕获到新事件并附加 logs 变量时,Alpine.js 检测到它并重新渲染 DOM 的相应部分。

英文:

> My understanding was that the x-init was only there to execute when the element is rendered.

No, x-init directive is called at initialization phase of an element. At that point Alpine.js has already created the data variables from x-data but it has not rendered anything (has not modified the DOM) yet. The x-init is the recommended place to put a function that e.g. calls an API then appends some variables defined in x-data or to create an event listener that (later) mutates the data like in your example.

After executing the functions from x-init, Alpine.js renders the component with the actual logs variable. When the event listener in your getLogs() function catches a new event and appends the logs variable, Alpine.js detects it and re-renders the respective parts of the DOM.

huangapple
  • 本文由 发表于 2023年3月12日 19:58:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75712946.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定