Svelte 变量不会在不使用 setInterval 强制更新的情况下从 localStorage 更新。

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

Svelte variable not updating from localStorage without using setInterval and forcing it

问题

我有一个应用程序,它将项目存储在localStorage中的位置,然后在HTML中显示这些项目。

我之所以想使用Svelte,其中一个原因是它具有响应式变量,但无论我尝试使用一个当localStorage.current_items发生变化时也会改变的响应式变量时,ItemList变量都不会发生变化。

唯一能让它工作的方法是使用setInterval,但这不是一个好的做法。我该如何使ItemList在localStorage.current_items字符串更改时正确地发生变化?

  1. <script lang="ts">
  2. import {
  3. getData,
  4. createItem,
  5. createLocation,
  6. closeItem,
  7. } from './lib/database.js';
  8. import LocationSelector from './lib/LocationSelector.svelte';
  9. import { flip } from 'svelte/animate';
  10. import { writable } from 'svelte/store';
  11. let DB = getData();
  12. // 从localstorage.items加载项目
  13. let ItemList = [];
  14. let Location;
  15. setInterval(() => {
  16. Location = localStorage.current_items;
  17. ItemList = JSON.parse(localStorage.current_items).items;
  18. }, 500);
  19. console.log(ItemList);
  20. let newItem = '';
  21. let filter_showClosed = false;
  22. function addNewItem(e) {
  23. e.preventDefault();
  24. console.log(newItem);
  25. const newItemInput = document.querySelector(
  26. '#newItemInput'
  27. ) as HTMLInputElement;
  28. createItem(JSON.parse(Location).id, newItem);
  29. newItem = '';
  30. }
  31. function newItemKeyDown(e) {
  32. if (e.keyCode === 13) {
  33. addNewItem(e);
  34. }
  35. }
  36. </script>
  37. <LocationSelector />
  38. <div class="app">
  39. <input
  40. type="text"
  41. id="newItemInput"
  42. bind:value={newItem}
  43. placeholder="Add a new item"
  44. on:keydown={newItemKeyDown}
  45. />
  46. <button
  47. id="filter_showClosed"
  48. data-active="false"
  49. on:click={function () {
  50. filter_showClosed = !filter_showClosed;
  51. let el = document.getElementById('filter_showClosed');
  52. if (filter_showClosed) {
  53. el.innerHTML = 'Hide closed';
  54. el.dataset.active = 'true';
  55. } else {
  56. el.innerHTML = 'Show closed';
  57. el.dataset.active = 'false';
  58. }
  59. }}>Show closed</button
  60. >
  61. <div class="list">
  62. {#each ItemList as item, index (item.id)}
  63. <div class="item {item.closed}" animate:flip={{ duration: 100 }}>
  64. {#if item.closed == false || (filter_showClosed == true && item.closed == true)}
  65. <div>
  66. <img
  67. src="/up.svg"
  68. class="item-icon"
  69. class:closed={item.closed == true}
  70. alt="move item up in priority"
  71. on:click={function () {
  72. // increaseLevel({ item });
  73. }}
  74. />
  75. {item.name} ({index})
  76. </div>
  77. <div>
  78. {#if item.closed == false}
  79. <img
  80. src="/close.svg"
  81. class="item-icon"
  82. alt="close item"
  83. on:click={function () {
  84. console.log(Location.id);
  85. closeItem(JSON.parse(Location).id, item.id);
  86. }}
  87. />
  88. {/if}
  89. </div>
  90. {/if}
  91. </div>
  92. {/each}
  93. </div>
  94. </div>
  95. <style>
  96. </style>

我尝试使用了writable方法,但这也没有起作用,因为变量仍然没有发生变化。

  1. import { writable } from 'svelte/store';
  2. const ItemList = writable([]);
  3. let Location = {};
  4. let newItem = '';
  5. let filter_showClosed = false;
  6. function addNewItem(e) {
  7. e.preventDefault();
  8. console.log(newItem);
  9. const newItemInput = document.querySelector(
  10. '#newItemInput'
  11. ) as HTMLInputElement;
  12. createItem(Location.id, newItem);
  13. newItem = '';
  14. }
  15. function newItemKeyDown(e) {
  16. if (e.keyCode === 13) {
  17. addNewItem(e);
  18. }
  19. }
  20. // 使用localStorage.current_items的当前值更新Location对象为一个对象
  21. Location = JSON.parse(localStorage.current_items);
  22. // 使用新位置的项目更新ItemList存储
  23. ItemList.set(Location.items);
英文:

I have an app that stores items into locations in localStorage and then displays the items in HTML.

One of the reasons i wanted to use Svelte was for reactive variables, but whenever I attempt to use a reactive variable that changes whenever localStorage.current_items changes, the ItemList variable doesn't change.

The only way I could get it to work is by using setInterval but that is not a great way to do it. How can I make it so that ItemList changes properly when the localStorage.current_items string changes.

  1. &lt;script lang=&quot;ts&quot;&gt;
  2. import {
  3. getData,
  4. createItem,
  5. createLocation,
  6. closeItem,
  7. } from &#39;./lib/database.js&#39;;
  8. import LocationSelector from &#39;./lib/LocationSelector.svelte&#39;;
  9. import { flip } from &#39;svelte/animate&#39;;
  10. import { writable } from &#39;svelte/store&#39;;
  11. let DB = getData();
  12. // load items from localstorage.items
  13. let ItemList = [];
  14. let Location;
  15. setInterval(() =&gt; {
  16. Location = localStorage.current_items;
  17. ItemList = JSON.parse(localStorage.current_items).items;
  18. }, 500);
  19. console.log(ItemList);
  20. let newItem = &#39;&#39;;
  21. let filter_showClosed = false;
  22. function addNewItem(e) {
  23. e.preventDefault();
  24. console.log(newItem);
  25. const newItemInput = document.querySelector(
  26. &#39;#newItemInput&#39;
  27. ) as HTMLInputElement;
  28. createItem(JSON.parse(Location).id, newItem);
  29. newItem = &#39;&#39;;
  30. }
  31. function newItemKeyDown(e) {
  32. if (e.keyCode === 13) {
  33. addNewItem(e);
  34. }
  35. }
  36. &lt;/script&gt;
  37. &lt;LocationSelector /&gt;
  38. &lt;div class=&quot;app&quot;&gt;
  39. &lt;input
  40. type=&quot;text&quot;
  41. id=&quot;newItemInput&quot;
  42. bind:value={newItem}
  43. placeholder=&quot;Add a new item&quot;
  44. on:keydown={newItemKeyDown}
  45. /&gt;
  46. &lt;button
  47. id=&quot;filter_showClosed&quot;
  48. data-active=&quot;false&quot;
  49. on:click={function () {
  50. filter_showClosed = !filter_showClosed;
  51. let el = document.getElementById(&#39;filter_showClosed&#39;);
  52. if (filter_showClosed) {
  53. el.innerHTML = &#39;Hide closed&#39;;
  54. el.dataset.active = &#39;true&#39;;
  55. } else {
  56. el.innerHTML = &#39;Show closed&#39;;
  57. el.dataset.active = &#39;false&#39;;
  58. }
  59. }}&gt;Show closed&lt;/button
  60. &gt;
  61. &lt;!-- &lt;button
  62. id=&quot;deleteClosed&quot;
  63. on:click={function () {
  64. let it = items;
  65. for (let i = 0; i &lt; it.length; i++) {
  66. if (it[i].closed == true) {
  67. it.splice(i, 1);
  68. }
  69. }
  70. items = it;
  71. sort_items(items);
  72. }}&gt;Delete all closed&lt;/button
  73. &gt; --&gt;
  74. &lt;div class=&quot;list&quot;&gt;
  75. {#each ItemList as item, index (item.id)}
  76. &lt;div class=&quot;item {item.closed}&quot; animate:flip={{ duration: 100 }}&gt;
  77. {#if item.closed == false || (filter_showClosed == true &amp;&amp; item.closed == true)}
  78. &lt;div&gt;
  79. &lt;img
  80. src=&quot;/up.svg&quot;
  81. class=&quot;item-icon&quot;
  82. class:closed={item.closed == true}
  83. alt=&quot;move item up in priority&quot;
  84. on:click={function () {
  85. // increaseLevel({ item });
  86. }}
  87. /&gt;
  88. {item.name} ({index})
  89. &lt;/div&gt;
  90. &lt;div&gt;
  91. {#if item.closed == false}
  92. &lt;img
  93. src=&quot;/close.svg&quot;
  94. class=&quot;item-icon&quot;
  95. alt=&quot;close item&quot;
  96. on:click={function () {
  97. console.log(Location.id);
  98. closeItem(JSON.parse(Location).id, item.id);
  99. }}
  100. /&gt;
  101. {/if}
  102. &lt;/div&gt;
  103. {/if}
  104. &lt;/div&gt;
  105. {/each}
  106. &lt;/div&gt;
  107. &lt;/div&gt;
  108. &lt;style&gt;
  109. &lt;/style&gt;

I tried using this writeable method, but that didn't work either as the variable still didn't change.

  1. import { writable } from &#39;svelte/store&#39;;
  2. const ItemList = writable([]);
  3. let Location = {};
  4. let newItem = &#39;&#39;;
  5. let filter_showClosed = false;
  6. function addNewItem(e) {
  7. e.preventDefault();
  8. console.log(newItem);
  9. const newItemInput = document.querySelector(
  10. &#39;#newItemInput&#39;
  11. ) as HTMLInputElement;
  12. createItem(Location.id, newItem);
  13. newItem = &#39;&#39;;
  14. }
  15. function newItemKeyDown(e) {
  16. if (e.keyCode === 13) {
  17. addNewItem(e);
  18. }
  19. }
  20. // Update the Location object with the current value of localStorage.current_items as an object
  21. Location = JSON.parse(localStorage.current_items);
  22. // Update the ItemList store with the new location&#39;s items
  23. ItemList.set(Location.items);

答案1

得分: 0

你应该使用一个完全封装了对 localStorage 访问的存储器。

类似这样的方式:

  1. function localStorageStore(key, initial) {
  2. const value = localStorage.getItem(key)
  3. const store = writable(value == null ? initial : JSON.parse(value));
  4. store.subscribe(v => localStorage.setItem(key, JSON.stringify(v)));
  5. return store;
  6. }

读取和写入就像普通的存储器一样,但在初始加载时,值来自存储,并且在设置值时,它也会写入存储。

英文:

You should use a store that fully wraps the access to localStorage.

Something like:

  1. function localStorageStore(key, initial) {
  2. const value = localStorage.getItem(key)
  3. const store = writable(value == null ? initial : JSON.parse(value));
  4. store.subscribe(v =&gt; localStorage.setItem(key, JSON.stringify(v)));
  5. return store;
  6. }

Reading and writing is just a regular store, but on initial load the value comes from the storage and on setting the value, it is also written to storage.

huangapple
  • 本文由 发表于 2023年1月9日 03:51:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75050813.html
匿名

发表评论

匿名网友

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

确定