经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » React » 查看文章
Jetpack?Compose对比React?Hooks?API相似度
来源:jb51  时间:2022/8/3 13:18:42  对本文有异议

众所周知Jetpack Compose设计理念甚至团队成员很多都来自React,在API方面参考了很多React(Hooks) 的设计,通过与React进行对比可以更好地熟悉Compose的相关功能。

Compose目前处于alpha版,虽然API还会调整,但是从功能上已经基本对齐了React,不会有大变化,本文基于1.0.0-alpha11。

React Component vs Composable

React中Component成为分割UI的基本单元,特别是16.8之后Hooks引入的函数组件,相对于类组件更利于UI与逻辑解耦。函数组件是一个接受Props作为参数并返回JSX node的函数:

  1. function Greeting(props) {
  2. return <span>Hello {props.name}!</span>;
  3. }

Compose同样使用函数作为组件:添加了@Composable注解的函数。而且借助Kotlin的DSL实现声明式语法,而无需额外引入JSX等其他标记语言,相对于React更加简洁:

  1. @Composable
  2. fun Greeting(name: String) {
  3. Text(text = "Hello $name!")
  4. }

JSX vs DSL

DSL相对于JSX更加简洁,可以直接使用原生语法表示各种逻辑。

loop

例如在JSX中实现一个循环逻辑,需要两种语言混编

  1. function NumberList(props) {
  2. return (
  3. <ul>
  4. {props.numbers.map((number) => (
  5. <ListItem value={number} />
  6. ))}
  7. </ul>
  8. );
  9. }

DSL中的循环就是普通的for循环

  1. @Composable
  2. fun NumberList(numbers: List<Int>) {
  3. Column {
  4. for (number in numbers) {
  5. ListItem(value = number)
  6. }
  7. }
  8. }

If statement

JSX 使用三元运算符表示条件

  1. function Greeting(props) {
  2. return (
  3. <span>
  4. {props.name != null
  5. ? `Hello ${props.name}!`
  6. : 'Goodbye.'}
  7. </span>
  8. );
  9. }

DSL直接使用IF表达式

  1. @Composable
  2. fun Greeting(name: String?) {
  3. Text(text = if (name != null) {
  4. "Hello $name!"
  5. } else {
  6. "Goodbye."
  7. })
  8. }

key component

React和Compose都可以通过key来标记列表中的特定组件,缩小重绘范围。

JSX使用key属性

  1. <ul>
  2. {todos.map((todo) => (
  3. <li key={todo.id}>{todo.text}</li>
  4. ))}
  5. </ul>

DSL使用key组件来标识Component

  1. Column {
  2. for (todo in todos) {
  3. key(todo.id) { Text(todo.text) }
  4. }
  5. }

Children Prop vs Children Composable

前面提到,React与Compose都使用函数组件创建UI,区别在于一个使用DSL,另一个依靠JSX。

React中,子组件通过props的children字段传入

  1. function Container(props) {
  2. return <div>{props.children}</div>;
  3. }
  4. <Container>
  5. <span>Hello world!</span>
  6. </Container>;

Compose中,子组件以@Composable函数的形式传入

  1. @Composable
  2. fun Container(children: @Composable () -> Unit) {
  3. Box {
  4. children()
  5. }
  6. }
  7. Container {
  8. Text("Hello world"!)
  9. }

Context vs Ambient(CompositionLocal)

对于函数组件来说,建议使用props/parameter传递数据,但是允许一些全局数据在组件间共享。React使用Context存放全局数据,Compose使用Ambient(alpha12中已改名CompositionLocal)存放全局数据

createContext : ambientOf

React使用createContext创建Context:

  1. const MyContext = React.createContext(defaultValue);

Compose使用ambientOf创建Ambient:

  1. val myValue = ambientOf<MyAmbient>()

Provider : Provider

React和Compose中都使用Provider注入全局数据,供子组件访问

  1. <MyContext.Provider value={myValue}>
  2. <SomeChild />
  3. </MyContext.Provider>
  1. Providers(MyAmbient provides myValue) {
  2. SomeChild()
  3. }

useContext : Ambient.current

React中子组件使用useContext hook访问Context

  1. const myValue = useContext(MyContext);

Compose中子组件通过单例对象访问Ambient

  1. val myValue = MyAmbient.current

useState vs State

无论React还是Compose,状态管理都是至关重要的。

React使用useState hook创建State

  1. const [count, setCount] = useState(0);
  2. <button onClick={() => setCount(count + 1)}>
  3. You clicked {count} times
  4. </button>

Compose使用mutableStateOf创建一个state,还可以通过by代理的方式获取

  1. val count = remember { mutableStateOf(0) }
  2. Button(onClick = { count.value++ }) {
  3. Text("You clicked ${count.value} times")
  4. }

还可以通过解构分别获取get/set

  1. val (count, setCount) = remember { mutableStateOf(0) }
  2. Button(onClick = { setCount(count + 1) }) {
  3. Text("You clicked ${count} times")
  4. }

或者通过by代理

  1. var count : Int by remember { mutableStateOf(false) }
  2. Button(onClick = { count++ }) {
  3. Text("You clicked ${count} times")
  4. }

Compose创建state时往往会remeber{ } 避免重绘时的反复创建state,相当于useMemo

useMemo vs remember

React使用useMemo hook用来保存那些不能随重绘反复计算的值,只有参数变化时才会重新计算。

  1. const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Compose中同样功能使用remember实现,同样通过参数作为重新计算的判断条件

  1. val memoizedValue = remember(a, b) { computeExpensiveValue(a, b) }

useEffect vs SideEffect

函数组件满足纯函数的要求:无副作用、无状态、即使多次运行也不会产生影响。但是总有一些逻辑不能以纯函数执行,例如 生命周期回调、日志、订阅、计时等,只能在特定时机执行,不能像一个纯函数那样可以执行多次而不产生副作用。

React中,useEffect 提供一个hook点,会在每次render时执行。注意 这不同于直接写在外面,当diff没有变化时不需要重新render,就不需要执行useEffect了

  1. useEffect(() => {
  2. sideEffectRunEveryRender();
  3. });

Compose中使用SideEffect处理副作用(早期版本是onCommit{ })

  1. SideEffect {
  2. sideEffectRunEveryComposition()
  3. }

useEffect(callback, deps) :DisposableEffect

跟useMemo一样可以接受参数,每次render时,只有当参数变化时才执行:

  1. useEffect(() => {
  2. sideEffect();
  3. }, [dep1, dep2]);

只在第一次render时执行的逻辑(相当于onMount),可以使用如下形式处理:

  1. useEffect(() => {
  2. sideEffectOnMount();
  3. }, []);

Compose中使用DisposableEffect:

  1. DisposableEffect(
  2. key1 = ""
  3. ...
  4. ) {
  5. onDispos{}
  6. }

Clean-up function : onDispose

useEffect通过返回一个function进行后处理

  1. useEffect(() => {
  2. const subscription = source.subscribe();
  3. return () => {
  4. subscription.unsubscribe();
  5. };
  6. });

DisposableEffect通过一个DisposableEffectDisposable进行后处理:

  1. DisposableEffect() {
  2. val dispose = source.subscribe()
  3. onDispose { //返回DisposableEffectDisposable
  4. dispose.dispose()
  5. }
  6. }

Hook vs Effect

React允许自定义Hooks封装可复用逻辑。Hooks可以调用useState、useEffect等其他hooks放方法,在特定的生命周期完成逻辑。自定义Hooks都使用useXXX的形式来命名

  1. function useFriendStatus(friendID) {
  2. const [isOnline, setIsOnline] = useState(null);
  3. useEffect(() => {
  4. function handleStatusChange(status) {
  5. setIsOnline(status.isOnline);
  6. }
  7. ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
  8. return () => {
  9. ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
  10. };
  11. });
  12. return isOnline;
  13. }

Compose没有命名上的要求,任何一个@Composable函数即可被用来实现一段可复用的处理Effect的逻辑:

  1. @Composable
  2. fun friendStatus(friendID: String): State<Boolean?> {
  3. val isOnline = remember { mutableStateOf<Boolean?>(null) }
  4. DisposableEffect {
  5. val handleStatusChange = { status: FriendStatus ->
  6. isOnline.value = status.isOnline
  7. }
  8. ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange)
  9. onDispose {
  10. ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange)
  11. }
  12. }
  13. return isOnline
  14. }

以上就是Jetpack Compose对比React Hooks API相似度的详细内容,更多关于Jetpack Compose对比React的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号