问题描述
抽象问题:
请考虑以下内容:
data class Data(val i: Int,val s: String = "")
fun <A1,A2,D> make(ctor: KFunction2<A1,D>,sideEffect: (D) -> D) =
{ a1: A1,a2: A2 -> sideEffect(ctor(a1,a2)) }
val makeData = make(::Data) {
it.also { println("Side effect: i=${it.i},s=${it.s}") }
}
我可以使用所有构造函数参数调用makeData以获取
Data
的实例,并且也带来一些副作用。但是,我
不能忽略参数,而使用构造函数的默认值:
val d1 = makeData(42,"hi")
val d2 = makeData2(42) // Error: No value passed for parameter 'p2'
我要实现的目标:
使用Kotlin React,我可以像这样声明属性:
external interface VideoListProps: RProps { var videos: List<Video> }
要使用render()中的组件,我可以编写:
child(VideoList::class) { attrs.videos = unwatchedVideos }
我不喜欢这样做有以下三个原因:(a)使用组件比TypeScript / TSX更为冗长,
(b)属性应声明为var,而属性应为只读(val),(c)没有强制要求实际上声明了成员;即使Props接口未将props.videos
声明为可为空,也可能在运行时以null
的形式出现。
Kotlin React的教程建议对接收器使用lambda,如下所示:
fun RBuilder.videoList(handler: VideoListProps.() -> Unit): ReactElement {
return child(VideoList::class) {
this.attrs(handler)
}
}
现在我可以像这样使用组件了:
videoList { videos = unwatchedVideos }
虽然调用站点现在看起来更加简洁,但是我现在必须针对我编写的每个组件复制/粘贴并修改lambda代码段。这比TypeScript更为冗长,在TypeScript中,我不需要这种构造。此外,由于this
现在指向RProps,所以videoList lambda无法访问RBuilder的其他成员。因此,如果我需要定义一个React key
,我很茫然,需要使用以前的child(...)语法。最后,上面的问题(c)仍然存在。
为了使它更好,我编写了以下帮助程序结构:
fun <P : RProps,A1> RBuilder.childWithProps(
klass: KClass<out Component<P,*>>,ctor: KFunction1<A1,P>
) =
{ a1: A1,handler: RHandler<P> -> child(klass.rClass,ctor(a1),handler) }
fun <P : RProps,A1,A2> RBuilder.childWithProps(
klass: KClass<out Component<P,ctor: KFunction2<A1,a2: A2,ctor(a1,a2),handler) }
// more for KFunction3,KFunction4,... up to a reasonable amount of members,e.g. 16
我承认这也很丑,但是我只需要写一次。现在,我可以像这样声明道具(注意val而不是var):
data class VideoListProps(val videos: List<Videos>) : RProps
每个组件的附加代码现在更加简洁:
val RBuilder.videoList get() = childWithProps(VideoList::class,::VideoListProps)
并像这样使用它:
videoList(watchedVideos) { /* you can set React key or children here if needed */ }
如果我忘记设置所有属性,Kotlin现在将其标记为错误。 现在所有内容看起来都很简洁,我编写的代码甚至比TypeScript / TSX少。剩下的唯一问题是,现在我总是必须传递所有成员,因为数据构造函数的任何默认值在包装器中仍然是必需的。 这是实际的问题。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)