我们先来看个例子:
Svelte
| 12
 3
 4
 5
 
 | <script>let name = 'John';
 </script>
 
 <h1>Hello {name}</h1>
 
 | 
React
| 12
 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 来模拟。
还记得官方的例子吧,咱们再来看看:
| 12
 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方法对外暴露两个参数,第一个参数是初始值名称,第二个是设置方法,下面开始模拟
| 12
 3
 4
 5
 
 | import { readable } from 'svelte/store';
 function useState(initValue){
 
 }
 
 | 
首先引入readable,然后生命useState函数,传入初始值参数。然后把readable放到useState中
| 12
 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
 }
 
 | 
上面就是基本骨架了,下面继续完善。
| 12
 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即可。
好了我们试试效果吧:
| 12
 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订阅下即可
| 12
 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 也是可以来模拟的,我们来看看:
| 12
 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是可以使用$直接改的
| 12
 3
 4
 
 | const [names,setNames] = useState2("world")setTimeout(()=>{
 $names = "hooks"
 },1000 * 3)
 
 | 
所以上面的模拟还是有点问题,还得我们前面有篇文章又讲到一个方式的,我们使用派生(derived)来解决。
| 12
 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
 }
 
 
 | 
这样调整之后再执行下面代码
| 12
 3
 4
 
 | const [names,setNames] = useState2("world")setTimeout(()=>{
 $names = "hooks"
 },1000 * 3)
 
 | 
就会报错了,需要改成
| 12
 3
 4
 
 | const [names,setNames] = useState2("world")setTimeout(()=>{
 setNames("hooks")
 },1000 * 3)
 
 | 
ok,你对实现一个useReducer感兴趣你也可以自己动手实现下。
当然这里就是为了说明Svelte的store的灵活,同时也是为了好玩,真正使用的话,如果这些写是画蛇添足了~