Svelte入门1:实现React的useEffect

225 阅读1分钟

导言

最近花一下午时间学习了Svelte 3的基础知识,上手的时候发现Svelte这么好用的框架,居然没有类似useEffect能将mounted和activated两种生命周期合并的API,于是自己写了一个:

useEffect的3种形式

react代码中的类型定义:

declare const UNDEFINED_VOID_ONLY: unique symbol;
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
type EffectCallback = () => (void | Destructor);
function useEffect(effect: EffectCallback, deps?: DependencyList): void;

1. useEffect(effect: EffectCallback)

合并了mounted和activated,每次render时都会先运行Destructor,再运行EffectCallback,这也是本文重点要用Svelte实现的部分

具体实现代码:

React 版本

import {useState, useEffect} from 'react'

const buttonStyle = {
  height: 40,
  width: 120
}
export default function App() {
  const [name, setName] = useState('world')
  useEffect(() => {
    console.log('enter')
    return () => {
      console.log('exit')
    }
  }, [name])
  function toggleName() {
    const newName = name === '' ? 'world' : ''
    setName(newName)
  }
  return (
    <div className="App">
      <h1>Hello {name}!</h1>
      <button onClick={() => toggleName()} style={buttonStyle}>toggle</button>
    </div>
  );
}

Svelte 版本

// onEffect.ts
import { afterUpdate, onMount } from "svelte";
type Destructor = () => void | void;
type EffectCallback = () => Destructor;
export function onEffect(effectFunction: EffectCallback) {
  let destructor: Destructor;
  onMount(() => {
    destructor = effectFunction();
    return () => {
      destructor && destructor();
    };
  });
  afterUpdate(() => {
    destructor && destructor();
    destructor = effectFunction();
  });
}
// App.svelte 吐槽下, 掘金居然没有svelte的语法高亮?
<script lang="ts">
  import { onEffect } from "./onEffect";
  let name = "world";
  onEffect(() => {
    console.log("enter");
    return () => {
      console.log("exit");
    };
  });
  function toggleName() {
    name = name === '' ? 'world' : ''
  }
</script>

<h1>Hello {name}!</h1>
<button on:click={toggleName}> toggle </button>
<style>
  button {
    height: 40px;
    width: 120px;
  }
</style>

2. useEffect(effect: EffectCallback, [])

相当于onMounted, 可以直接用Svelte的onMounted实现

3. useEffect(effect: EffectCallback, [a, b])

对于本身就是响应式的Svelte来说,不需要做依赖管理,依赖变化时afterUpdate一定会被调用,因此可以复用第一种形式的代码