写在前面

本文中提及的 use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专注于业务与 UI 组件。

这是系列文章的第 10 篇,前文:

阅读全文 »

新改进

在 Kotlin 2.1.0 版本引入了一个新的改进:Improved overload resolution for functions with generic types

官方描述,是对泛型函数的重载解析进行了加强,例如在过去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class KeyValueStore<K, V> {
fun store(key: K, value: V) {} // 1
fun store(key: K, lazyValue: () -> V) {} // 2
}

fun <K, V> KeyValueStore<K, V>.storeExtension(key: K, value: V) {} // 1
fun <K, V> KeyValueStore<K, V>.storeExtension(key: K, lazyValue: () -> V) {} // 2

fun test(kvs: KeyValueStore<String, Int>) {
// Member functions
kvs.store("", 1) // Resolves to 1
kvs.store("") { 1 } // Resolves to 2

// Extension functions
kvs.storeExtension("", 1) // Resolves to 1
kvs.storeExtension("") { 1 } // Doesn't resolve
}

对于类中泛型函数的重载是可以正确解析的,你传递一个 lambda 作为参数不会被解析到 函数1,但是在扩展函数的情况下,编译器会报错提示你存在歧义的重载函数,它无法将上边例子中的 lambda 解析到 storeExtension(key: K, lazyValue: () -> V)

在 Compose 中实现 React 的 useState?

这个问题对于我们日常开发可能影响不大,但是对于库作者而言可能有些难受。例如在 ComposeHooks 中,我一直期望实现类似 React 中 useState 的效果,即 setState 函数既能接收值,也能接收一个 (oldStateValue)=>newStateValue 函数,因为这两者在逻辑上是几乎是一致的,你只需要对 lambda 求值,就可以使用同样的逻辑来执行更新状态。

在 React 中你可以这样写:

1
2
3
4
const [state, setState] = useState(0);

setState(1); // 更新状态值为1
setState((value) => value + 1); // 更新状态值加1

这种写法非常灵活,我们经常需要使用当前状态的值进行计算,将结果作为新值赋值给状态,这是一个非常常见的场景。

这一切都是因为 JavaScript 是弱类型语言,也就是解构出的 setState 既可以接收一个函数作为参数,也可以接收一个值作为参数,但是在 Kotlin 中无法实现 Kotlin 也不支持联合类型,但是这个新特性让我看到了转机。

Arrow 前来助力

arrow 是一个非常棒的 Kotlin 函数式编程库,它扩展了 Kotlin 在函数式编程上的应用场景,在 ComposeHooks 中也有很多地方运用了这个库。

这里我们主要使用的是 Either<L,R> 这个容器类型,这个类型包装了左值与右值,其结果只能是其中之一,非常类似 Kotlin 原生的 Result 类型,它提供了方便的扩展函数 left()right() 来快速的创建 Either 实例。

回到正题,我们的 setState 函数其实是这样的一个函数:

1
typealias SetValueFn<T> = (T) -> Unit

现在它只能接收一个 值 作为参数,而不能接收一个 lambda,那如果这里的 T 的类型是这样的呢:

1
Either<T, (T) -> T>

它是一个容器类型,它的左值是值,右值是一个函数,这时我们只需要为这个函数类型的调用操作符进行重载:

1
2
3
4
5
6
typealias SetterEither<T> = Either<T, (T) -> T>

operator fun <T> SetValueFn<SetterEither<T>>.invoke(leftValue: T) = this(leftValue.left())

operator fun <T> SetValueFn<SetterEither<T>>.invoke(rightValue: (T) -> T) = this(rightValue.right())

然后借助 Eitherfold 函数我可以方便的处理左右值:

1
2
3
4
5
6
7
8
GetStateHolder(
state = state,
setValue = { value: SetterEither<T & Any> ->
val newValue = value.fold({ it }, { it(state.value) }) // 处理左右值情况
state.value = newValue
},
getValue = { state.value }
)

左值直接取值,右值传递当前状态的值执行 lambda 进行求值。

现在你只需 import 这个 invoke 重载,就可以获得在 React 中使用 useState 一样的体验了。

1
2
3
4
5
6
7
8
9
import xyz.junerver.compose.hooks.invoke

val (state, setState) = useGetState(default)
fun set(num:Int) {
setState(num) // 传递值
}
fun add(){
setState{ it +1 } // 传递函数
}

查看更多

写在前面

本文中提及的use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专注于业务与 UI 组件。

这是系列文章的第 9 篇,前文:

在前面的文章中,我们简单的介绍过 useRequest 这个 hook,他被设计的高度抽象,同时也极易扩展,在下面的两个章节中,我将举两个例子,让你在业务中更好的使用它

阅读全文 »

在实际开发中,我们经常会遇到一些字段在应用中需要反复使用。

过去最常见的做法就是在 Application 中申明一个属性,使用它来暂存这个字段,这是非常常见的内存持久化方案,这些暂存内容会在应用退出后丢失,属于短期持久化

另一个场景就是使用 MMKV 这样的键值对持久化工具,将需要持久化的内容保存到本地文件,这些内容退出后不会丢失,再次打开应用时会重新读取加载,属于长期持久化

在 Compose 中需要我们可以使用 junerver/ComposeHooks 中的 usePersistent 来轻松做到这一点。

阅读全文 »

前段时间一直在忙鸿蒙相关的工作,最近忙里抽闲,总结一下之前在写 ComposeHooks  项目的一些小小心得。

DSL,其实在这里更多指的是利用作用域概念,限定函数闭包内的函数调用行为(下面称之为作用域内行为)。

在之前的文章:# 在 Kotlin 中巧妙的使用 DSL 封装 SpannableStringBuilder

提到了编写 DSL 的一些小心得,总结如下:

阅读全文 »

写在前面

本文中提及的 use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专心于业务与UI组件。

这是系列文章的第8篇,前文:

阅读全文 »


highlight: androidstudio

写在前面

本文中提及的use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专注于业务与UI组件。

这是系列文章的第7篇,前文:

阅读全文 »

写在前面

本文中提及的 use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专心于业务与 UI 组件。

这是系列文章的第 6 篇,前文:

阅读全文 »

写在前面

本文中提及的 use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专心于业务与 UI 组件。

这是系列文章的第五篇,前文:

阅读全文 »

写在前面

本文中提及的 use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专心于业务与 UI 组件。

这是系列文章的第四篇,前文:

阅读全文 »

咋一看标题你可能会觉得这有什么好研究的,请仔细看我的描述:在父组件中调用子组件的函数!

众所周知,如果我们希望让子组件调用父组件的函数,可以如下方式:

那么问题来了,父组件如何调用子组件的函数呢?

阅读全文 »

”总所周知“,在 Compose 中有个思想叫做状态提升,在之前的文章Compose 学习笔记 2 - LaunchedEffect、状态与 状态管理中我们曾提及过。

状态提升的目的是为了让我们的组件尽可能的”无状态“,无状态的优点:

  • 可复用,组件只负责组件的职责,不持有或者少持有状态
  • 可测试,组件不持有状态,更接近于纯函数,相同输入必然有相同输出

状态提升的想法很好,但是实践的时候可能并不美妙。

阅读全文 »


还记得: 使用 ahooks 中的 useRequest 轻松管理React中的网络请求 这篇文章么?

现在我将 ahooks 带到了 Compose 开发中!

在Compose项目中,你是如何进行网络请求,管理状态的?ViewModel?还是 LaunchedEffect 配合 State

他们看起来都不够优雅,我们真的需要在 Compose 中创建这么多VM么?

还有更优雅的方式么?

来了解一下 junerver/ComposeHooks 吧,也许它会让你在 Compose 开发中更加得心应手,更多的专注于组件而非复杂的状态管理。

阅读全文 »

我正在参加「掘金·启航计划」

关注 Kotlin 的大多数开发中可能都是 Android 开发者吧,大家基本也都是慢慢从 Java 逐步迁移到 Kotlin。

得益于 Kotlin 与 Java 之间良好的互通性,有的时候可能我们写代码还是比较随性的,尤其是依旧按照自己过去写 Java 的编程习惯,书写 Kotlin 代码。

但实际上 Kotlin 与 Java 之间编码风格还是有很大的差异的,你的代码可能还是 Java 的咖啡味。现在请你“暂时”忘记 Java 编码规范,放下成见,看一下 Kotlin 有哪些有趣之处。

阅读全文 »

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

关于 ahooks

2022年的今天,在 React 中使用 Hook 已经是常规的不能再常规的操作了,我们会大量的通过组合 React 提供的 Hook,创建属于自己业务的专属自定义 Hook,亦或是各种工具 Hook。

阿里前端团队出品的 ahooks 正是这样一套 Hook 工具集,里面提供数十个常用的 Hook,可以极大的方便我们的日常开发。

今天我们要着重介绍的。就是 ahooks 项目中最为重量级的一个 hook ,useRequest

阅读全文 »

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

这是我关于 ahooks - useRequest 系列文章的第三篇,前两篇请查看:

通过前两篇文章我们已经基本了解了关于服务端状态管理的概念,也通过 useRequest 体验了一系列有趣的功能,认识到了其强大之处。

本文我们将继续介绍 useRequest 的进阶用法,主要是:swr 。

阅读全文 »

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

在之前的文章:从零开始学习React-5:状态与状态管理,我们简单的介绍目前最流行的状态管理库 redux。今天我们介绍由 redux 团队推出的,可以更高效、更方便使用 redux 的另一个工具:Redux-Toolkit(简称:RTK)

阅读全文 »

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

在应用里集成第三方登录是比较常见的需求,尤其是微信登录,但是由于微信官方文档许久没有维护,直接上手还是会走一些弯路,本文将介绍当前移动端集成微信登录的方法。

阅读全文 »


theme: devui-blue

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

通过前面的几篇文章,我们已经大致的了解了 React 中的一些概念,也通过 cra 脚手架创建了一个正式的项目,接下来我们将使用 Antd 组件库开发一些简单的用例。并通过这个例子进一步了解 React 函数式组件、HOOK 、状态管理等概念。

在这个系列文章的第一章,我们就介绍过了 React 的状态,以及一种状态管理思想:状态提升,但是在面对一些复杂场景,状态提升就显得有些麻烦了,多个不同层级的组件状态,提升到共有的顶层组件,然后通过 props 在组件之间传递,一来代码量上提升很多,二来如果涉及修改,就会比较麻烦。

有的中间组件可能并不需要使用这些状态,或者函数,但是为了传递到目标组件还是需要在 props 中进行声明,显得非常的笨重。我写了一个 TodoList 的小例子,来说明这种尴尬的情况。

阅读全文 »
0%