之前尝试不用编译器插件的前提下实现 compose Remember,想到的方案是牺牲一定的使用自由度,调用顺序获得 remember
能力,今天看了 ReactJS,其实他就是这样实现的。
https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e
useRef/useMemo
类似 by remember
,不会触发变化,但是在此组件实例中的值会被记住,不会因重新渲染而变化。 useState
类似 by remember{ mutableStateOf }
可触发变化
compose 的 api 更好理解些。
由于 JS 是弱类型,ReactJS 有很多隐式的契约,比如:
1
2
3
4
5
6
7
8
9
const [state,setState] = useState(false);
// setState 可传一个函数,其参数为当前状态,返回值为新状态
setState((prevState)=>!prevState);
// 也可传一个值
setState(!state)
// 甚至可以传任意不正确的函数,或任意类型
setState(()=>{}) // 无返回值
1
2
3
4
5
6
7
8
9
10
<li key={item.id}
ref={(node)=>{
// node == null 时代表需要清除,即当前节点要被移除了
if(node==null) {
getRefs().delete(item.id);
} else {
getRefs().set(item.id, node);
}
}}
>item</li>
类型不确定,让 API 学习成本剧增,也极易写出编译正常而实际逻辑并不正确的代码。类型确定的 Kotlin ,则可以使用:
1
2
3
4
5
6
7
8
DisposableEffect {
// do something
// DisposableEffect 最后必须是 onDispose ,否则编译不过
onDispose {
// do when dispose
}
}
对应的 js 写法是:
1
2
3
4
5
6
7
8
useEffect(()=>{
// do something
// 以下 dispose function 是可选的
return () => {
// do when dispose
}
})
上例中 DisposableEffect
表意明确,而 useEffect
则有更强的自由度
,但理解及记忆此 api 的学习成本则更高。
这是 JavaScript 弱类型不得已而为之,在 Kotlin/TypeScript 强类型语言中,不应照抄,避免使用 Any?
类型
Ref 是命令式的,应尽量避免使用。