代码之家  ›  专栏  ›  技术社区  ›  nvioli

当嵌套组件更新时,Svelte store不会在更改时触发

  •  6
  • nvioli  · 技术社区  · 7 年前

    比如说,我想创建一个具有纤细感的多色选择器,也许可以让用户选择前景色和背景色。我的数据模型如下所示:

    {
      foreground: {
        r: 100,g:100,b:100
      },
      background: {
        r: 200,g:200,b:200
      }
    };
    

    所以我的应用程序。js是

        import AppUI from './App.html';
    import { Store } from 'svelte/store.js';
    
    const defaultData = {
      foreground: {
        r: 100,g:100,b:100
      },
      background: {
        r: 200,g:200,b:200
      }
    };
    
    const store = new Store(defaultData);
    
    window.store = store; // useful for debugging!
    
    store.onchange(() => console.log('something changed'));
    
    var app = new AppUI({
      target: document.querySelector( '#main' ),
      store
    });
    
    export default app;
    

    然后我可以建立一个 RGBSelector

      <input type="range" min=0 max=255 step=1 bind:value=data.r/>{{data.r}}
      <input type="range" min=0 max=255 step=1 bind:value=data.g/>{{data.g}}
      <input type="range" min=0 max=255 step=1 bind:value=data.b/>{{data.b}}
    

    还有我的 App.html 非常简单:

    foreground:
    <RGBSelector bind:data=$foreground/>
    
    background:
    <RGBSelector bind:data=$background/>
    
    <script>
      import RGBSelector from './RGBSelector.html';
    
      export default {
        components: {
          RGBSelector
        }
      };
    </script>
    

    大多数情况下,这似乎有效。范围输入中的双向绑定正在工作(标签更新),存储甚至正在更新(通过检查验证) store._state 在控制台中)。所以我相信 bind 中的关键字 RGB选择器 正在将更改传递到 App ,这反过来又是 绑定 把他们送到商店。

    问题是 store.onchange 处理程序未启动。谁能看出我做错了什么?

    完整示例: https://glitch.com/edit/#!/nonstop-hourglass

    1 回复  |  直到 7 年前
        1
  •  3
  •   Rich Harris    7 年前

    这是Svelte中的一个bug,不是你的应用程序!事实证明,组件绑定不能很好地发挥作用 store 这个 bind:data=$foreground 正在更新 $foreground 在你的 <App> 组件,而不是更新 foreground 在你的店里。

    在此处跟踪问题: https://github.com/sveltejs/svelte/issues/1100

    遗憾的是,在我们解决这个问题之前,没有一个很好的解决方法,你需要这样做:

    foreground: <RGBSelector bind:data=foreground/>
    background: <RGBSelector bind:data=background/>
    text: <Textinput bind:value=text/>
    
    <script>
      import RGBSelector from './RGBSelector.html';
      import Textinput from './Textinput.html';
    
      export default {
        components: {
          RGBSelector, Textinput
        },
    
        oncreate() {
          this.observe('foreground', foreground => {
            this.store.set({ foreground });
          });
    
          this.observe('background', background => {
            this.store.set({ background });
          });
    
          this.observe('text', text => {
            this.store.set({ text });
          });
        }
      };
    </script>
    

    在JS文件中:

    var app = new App({
      target: document.body,
      data: defaultData,
      store
    });
    

    如果更改可以双向进行,您还需要观察存储属性,注意防止无限更新循环:

    // inside `oncreate` — would also need to do this
    // for `background` and `text`
    let foregroundUpdating = false;
    
    this.observe('foreground', foreground => {
      if (foregroundUpdating) return;
      foregroundUpdating = true;
      this.store.set({ foreground });
      foregroundUpdating = false;
    });
    
    this.store.observe('foreground', foreground => {
      if (foregroundUpdating) return;
      foregroundUpdating = true;
      this.set({ foreground });
      foregroundUpdating = false;
    });
    

    像这样重新创建绑定的功能显然有点麻烦,所以我们会尽快修复这个bug。