我们先来看个例子:
Svelte
1 2 3 4 5
| <script> let name = 'John'; </script>
<h1>Hello {name}</h1>
|
React
1 2 3 4 5 6 7
| import { useState } from 'react';
export default function Name() { const [name] = useState('John');
return <h1>Hello {name}</h1>; }
|
从上面的例子可以看出,Svelte
的反应性是非常的简洁的,只需要使用let
进行声明即可。再看下React
是我们熟悉的hooks的方式。
今天我们要谈的看标题名称就明白啥意思了,如果你觉得React的Hooks很好用,比如useState,也想在Svelte中这么使用,当然了只是想这样咱们不弹对错。我们应该怎么做呢?
咱们前面学习了Svelte
的stores
大家还记得吧,最常使用的是writable
,今天咱们先使用不常用的readable
来模拟。
还记得官方的例子吧,咱们再来看看:
1 2 3 4 5 6 7 8 9 10 11
| import { readable } from 'svelte/store';
const time = readable(null, set => { set(new Date());
const interval = setInterval(() => { set(new Date()); }, 1000);
return () => clearInterval(interval); });
|
这个例子是定时返回事件对象,从这个例子我们可以了解readable的使用规则
store = readable(value?: any, start?: (set: (value: any) => void) => () => void)
我们要是想使用它模拟useState,该怎么处理呢?
我们先来看看useState的语法
const [name,setName] = useState('John')
useState方法对外暴露两个参数,第一个参数是初始值名称,第二个是设置方法,下面开始模拟
1 2 3 4 5
| import { readable } from 'svelte/store';
function useState(initValue){ }
|
首先引入readable,然后生命useState函数,传入初始值参数。然后把readable放到useState中
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { readable } from 'svelte/store';
function useState(initValue){ const nameStore = readable(initValue, set => { });
return [nameStore,setValue] }
export { useState }
|
上面就是基本骨架了,下面继续完善。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { readable } from 'svelte/store';
function useState(initValue){ let setValue const nameStore = readable(initValue, set => { setValue = set })
return [nameStore,setValue] } export { useState }
|
setValue是设置内容的,我们看看readable的官方例子就知道,我们把set方法赋给setValue即可。
好了我们试试效果吧:
1 2 3 4 5 6 7 8
| <script> import { useState } from './hooks.js' let nameVal = 'world'; const [name,setName] = useState(nameVal) setName("useState") </script>
<h1>Hello {name}</h1>
|
结果是报错:setName is not a function
我们需要让nameStore订阅下即可
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { readable } from 'svelte/store';
function useState(initValue){ let setValue const nameStore = readable(initValue, set => { setValue = set }) nameStore.subscribe(value => {}) return [nameStore,setValue] } export { useState }
|
同时我们还需要修改下,还记得之前讲的自动订阅吧,就是加$
REPL
通过这个例子我们会发现使用writable
也是可以来模拟的,我们来看看:
1 2 3 4 5 6 7 8 9 10 11
| import { writable } from 'svelte/store';
function useState(initValue){ const nameStore = writable(initValue) let setValue = ((val) => { nameStore.update((currentVal) => currentVal = val) }) return [nameStore, setValue] export { useState }
|
架子基本上差不多的,区别就是把readable
换成了writable
,这样有没有问题呢?大家知道writable
声明后的nameStore
是可以使用$
直接改的
1 2 3 4
| const [names,setNames] = useState2("world") setTimeout(()=>{ $names = "hooks" },1000 * 3)
|
所以上面的模拟还是有点问题,还得我们前面有篇文章又讲到一个方式的,我们使用派生(derived)来解决。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { writable,derived } from 'svelte/store';
function useState(initValue){ const nameStore = writable(initValue) let setValue = ((val) => { nameStore.update((currentVal) => currentVal = val) }) const readableStore = derived(nameStore, $nameStore => $nameStore) return [readableStore, setValue] } export { useState }
|
这样调整之后再执行下面代码
1 2 3 4
| const [names,setNames] = useState2("world") setTimeout(()=>{ $names = "hooks" },1000 * 3)
|
就会报错了,需要改成
1 2 3 4
| const [names,setNames] = useState2("world") setTimeout(()=>{ setNames("hooks") },1000 * 3)
|
ok,你对实现一个useReducer
感兴趣你也可以自己动手实现下。
当然这里就是为了说明Svelte的store的灵活,同时也是为了好玩,真正使用的话,如果这些写是画蛇添足了~