导言
最近花一下午时间学习了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一定会被调用,因此可以复用第一种形式的代码