【问题标题】:How to listen the state changes in svelte like useEffect如何像 useEffect 一样监听 svelte 中的状态变化
【发布时间】:2021-06-07 14:04:42
【问题描述】:

我已经阅读了一些关于状态变化监听器的文章,因为我是一个非常初学者的 svelte 环境,所以我不知道什么是最有效的监听状态变化的方法。

让我们将状态变量设为XY

方法一:

$: if (X||Y) {
    console.log("yes");
}

方法二:

使用afterUpdateonDestroy 的组合

回复:https://svelte.dev/repl/300c16ee38af49e98261eef02a9b04a8?version=3.38.2

import { afterUpdate, onDestroy } from 'svelte';

export function useEffect(cb, deps) {
    let cleanup;
    
    function apply() {
        if (cleanup) cleanup();
        cleanup = cb();
    }
    
    if (deps) {
        let values = [];
        afterUpdate(() => {
            const new_values = deps();
            if (new_values.some((value, i) => value !== values[i])) {
                apply();
                values = new_values;
            }
        });
    } else {
        // no deps = always run
        afterUpdate(apply);
    }
    
    onDestroy(() => {
        if (cleanup) cleanup();
    });
}

方法三:

使用writablesubscribe


<script>
import { writable } from 'svelte/store';
const X = writable(0);
const Y = writable(0);


X.subscribe(value => {
    console.log("X was changed", value);
});


Y.subscribe(value => {
      console.log("Y was changed", value);
});

</script>

<button on:click={(e)=>{
    X.update((val)=>val++)
}}>Change X</button>
<button on:click={(e)=>{
    Y.update((val)=>val++)
}}>Change Y</button>

【问题讨论】:

  • 最有效的方法取决于您的用例。对此没有万能的解决方案。
  • 常用的方法是方法一,为什么要复杂一些?
  • 当我尝试使用方法 1 时,它并不总是触发。 svelte.dev/repl/3cb4c229c334488883db49383656ec26?version=3.38.2
  • 您链接的代码有一个错误,因为它使用了未定义的变量name
  • 是的,它总是触发不是吗?

标签: state use-effect svelte


【解决方案1】:

反应式语句

Svelte 没有等效的 useEffect。相反,Svelte 有响应式语句。

// Svelte
// doubled will always be twice of single. If single updates, doubled will run again.
$: doubled = single * 2

// equivalent to this React

let single = 0
const [doubled, setDoubled] = useState(single * 2)

useEffect(() => {
  setDoubled(single * 2)
}, [single])

这可能看起来很神奇,因为您没有定义依赖项或拆卸函数,但 Svelte 会在后台处理所有这些。 Svelte 足够聪明,可以找出依赖关系,并且只根据需要运行每个响应式语句。

因此,如果您想在每次值更新时运行回调,您可以简单地执行此操作。

<script>
  let value = ''
  $: console.log(value)
</script>

<input type='text' name='name' bind:value />

简而言之,这将在每次输入值更改时控制台记录输入值。

重新创建您的建议

方法一

这是尽可能简洁的方法,并且是我聆听状态变化的首选方法,除非我需要更复杂的东西。

$: if(x || y) console.log('yes')

但请注意,这里可能存在一个微妙的错误。如果xy 都为真然后变为假(例如,它们都成为空字符串),则此语句将不会运行。

方法二

在这里,您基本上重新创建了 React 的 useEffect。这行得通,但是您可以使用响应式语句大大简化 REPL 中的实现。

<script>
    let count = 1;
    $: console.log(count)
</script>

<input type="number" bind:value={count}>

方法3

Store 非常适合在不使用 props 或上下文的情况下在组件之间传递数据。查看此答案了解更多信息:https://stackoverflow.com/a/67681054/11506995

不过,在这种情况下,我们可以(再次)使用常规反应式上下文来简化一切。

<script>
  let x = 0
  let y = 0

  $: console.log('x was changed', x)
  $: console.log('y was changed', y)
</script>

<button on:click={() => x++}>Change x</button>
<button on:click={() => y++}>Change x</button>

我还有一个详细的答案,将 React 的 context/useEffect 与 Svelte 的 context/stores/reactive 语句在 Understanding Context in Svelte (convert from React Context) 中进行比较

https://stackoverflow.com/a/67681054/11506995

【讨论】:

    猜你喜欢
    • 2021-06-16
    • 2011-01-31
    • 2014-12-11
    • 2017-05-31
    • 2015-05-23
    • 2021-02-17
    • 2021-08-13
    • 1970-01-01
    相关资源
    最近更新 更多