Jetpack Compose对比React Hooks API相似度

目录
  • React Component vs Composable
  • JSX vs DSL
    • loop
    • If statement
    • key component
  • Children Prop vs Children Composable
  • Context vs Ambient(CompositionLocal)
    • createContext : ambientOf
    • Provider : Provider
    • useContext : Ambient.current
  • useState vs State
  • useMemo vs remember
  • useEffect vs SideEffect
    • useEffect(callback, deps) :DisposableEffect
    • Clean-up function : onDispose
  • Hook vs Effect

众所周知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的函数:

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

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

@Composable
fun Greeting(name: String) {
  Text(text = "Hello $name!")
}

JSX vs DSL

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

loop

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

function NumberList(props) {
  return (
    <ul>
      {props.numbers.map((number) => (
        <ListItem value={number} />
      ))}
    </ul>
  );
}

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

@Composable
fun NumberList(numbers: List<Int>) {
  Column {
    for (number in numbers) {
      ListItem(value = number)
    }
  }
}

If statement

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

function Greeting(props) {
  return (
    <span>
      {props.name != null
        ? `Hello ${props.name}!`
        : 'Goodbye.'}
    </span>
  );
}

DSL直接使用IF表达式

@Composable
fun Greeting(name: String?) {
  Text(text = if (name != null) {
    "Hello $name!"
  } else {
    "Goodbye."
  })
}

key component

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

JSX使用key属性

<ul>
  {todos.map((todo) => (
    <li key={todo.id}>{todo.text}</li>
  ))}
</ul>

DSL使用key组件来标识Component

Column {
  for (todo in todos) {
    key(todo.id) { Text(todo.text) }
  }
}

Children Prop vs Children Composable

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

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

function Container(props) {
  return <div>{props.children}</div>;
}
<Container>
  <span>Hello world!</span>
</Container>;

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

@Composable
fun Container(children: @Composable () -> Unit) {
  Box {
    children()
  }
}
Container {
  Text("Hello world"!)
}

Context vs Ambient(CompositionLocal)

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

createContext : ambientOf

React使用createContext创建Context:

const MyContext = React.createContext(defaultValue);

Compose使用ambientOf创建Ambient:

val myValue = ambientOf<MyAmbient>()

Provider : Provider

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

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

useContext : Ambient.current

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

const myValue = useContext(MyContext);

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

val myValue = MyAmbient.current

useState vs State

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

React使用useState hook创建State

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

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

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

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

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

或者通过by代理

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

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

useMemo vs remember

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

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

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

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

useEffect vs SideEffect

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

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

useEffect(() => {
  sideEffectRunEveryRender();
});

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

SideEffect {
  sideEffectRunEveryComposition()
}

useEffect(callback, deps) :DisposableEffect

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

useEffect(() => {
  sideEffect();
}, [dep1, dep2]);

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

useEffect(() => {
  sideEffectOnMount();
}, []);

Compose中使用DisposableEffect:

DisposableEffect(
   key1 = "",
   ...
) {
  onDispos{}
}

Clean-up function : onDispose

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

useEffect(() => {
  const subscription = source.subscribe();
  return () => {
    subscription.unsubscribe();
  };
});

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

DisposableEffect() {
  val dispose = source.subscribe()
  onDispose { //返回DisposableEffectDisposable
     dispose.dispose()
  }
}

Hook vs Effect

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

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });
  return isOnline;
}

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

@Composable
fun friendStatus(friendID: String): State<Boolean?> {
  val isOnline = remember { mutableStateOf<Boolean?>(null) }
  DisposableEffect {
    val handleStatusChange = { status: FriendStatus ->
      isOnline.value = status.isOnline
    }
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange)
    onDispose {
		ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange)
	}
  }
  return isOnline
}

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

(0)

相关推荐

  • Android Jetpack组件Navigation导航组件的基本使用

    目录 1.Navigation 基本概念 2.Navigation 使用入门 2.1 添加Navigation依赖 2.2 创建导航图 2.3 导航图中添加目的地Fragment 2.4 Activity添加 NavHost 2.5 LoginFragment 代码编写 2.6 welcomeFragment 代码编写 总结 本篇主要介绍一下 Android Jetpack 组件 Navigation 导航组件的 基本使用 当看到 Navigation单词的时候 应该就大概知道 这是一个关于导航

  • ReactHooks批量更新state及获取路由参数示例解析

    目录 一.如何批量更新 控制台输出 二.Hooks如何获取路由参数 执行效果 一.如何批量更新 在[Hooks]中如果单独的进行状态的更新可能会导致页面的多次渲染: import { useState } from 'react'; import { unstable_batchedUpdates } from 'react-dom';//批量更新状态时使用 import React from 'react'; const Example = () => { const [count, setC

  • 详解react hooks组件间的传值方式(使用ts)

    目录 父传子 子传父 跨级组件(父传后代) 父传子 通过props传值,使用useState来控制state的状态值 父组件 Father.tsx里: 子组件 Child.tsx里: 展示效果: 子传父 跟react的方式一样,像子组件传入回调函数,通过接收子组件的返回值,再去更新父组件的state 父组件,Father.tsx里: 子组件,Child.tsx里: 展示效果: 子传父优化版,使用useCallback存放处理事件的函数 父组件,Father.tsx里: 子组件,Child.tsx

  • 利用Jetpack Compose实现主题切换功能

    目录 前言 color.kt Theme.kt 关于compositionLocalOf 完整代码 前言 新建的Compose项目默认的 Material 主题为我们提供了一些颜色,但对我这种花里胡哨的人来说根本不够呀. 所以系统提供的主题不能满足需求时候可以自己配置主题 compose 实现换肤很简单 之前xml方法可复杂了 通过LayoutInflater调用inflate方法加载XML布局,在inflate方法中有一个createViewFromTag,再根据LayoutInflater当

  • Jetpack Compose实现列表和动画效果详解

    目录 创建一个列表消息卡片 可交互的动画效果 创建一个列表消息卡片 到目前为止,我们只有一个消息的卡片,看上去有点单调,所以让我们来改善它,让它拥有多条信息.我们需要创建一个能够显示多条消息的函数.对于这种情况,我们可以使用 Compose 的 LazyColumn 和 LazyRow.这些 Composable 只渲染屏幕上可见的元素,所以它们的设计对于长列表来说很有效果.同时,它们避免了 RecyclerView 与 XML 布局的复杂性. import androidx.compose.f

  • Android Jetpack Compose实现列表吸顶效果

    目录 stickyHeader 实体类 加载假数据 吸顶标题 二级条目 完整代码 效果图 安卓传统的 Recyclerview 打造悬浮头部StickyHeader的吸顶效果,十分麻烦,而在Compose中就简单多了 stickyHeader Compose设计的时候考虑得很周到,他们提供了stickyHeader 作用就是添加一个粘性标题项,即使在它后面滚动时也会保持固定.标头将保持固定,直到下一个标头取而代之. 参数key - 表示唯一的密钥键. 它不允许对列表出现使用相同的键.密钥的类型应

  • 教你在react中创建自定义hooks

    一.什么是自定义hooks 逻辑复用 简单来说就是使用自定义hook可以将某些组件逻辑提取到可重用的函数中. 自定义hook是一个从use开始的调用其他hook的Javascript函数. 二.不使用自定义hook时 例1:当我们整个页面需要获取用户鼠标移动的坐标时,不使用hook的代码,我们可以这样写 const [position, setPosition] = useState({ x: 0, y: 0 }) useEffect(() => { const move = (e) => {

  • Jetpack Compose对比React Hooks API相似度

    目录 React Component vs Composable JSX vs DSL loop If statement key component Children Prop vs Children Composable Context vs Ambient(CompositionLocal) createContext : ambientOf Provider : Provider useContext : Ambient.current useState vs State useMemo

  • Compose声明式代码语法对比React Flutter SwiftUI

    目录 前言 1.Stateless 组件 2.Stateful 组件 3. 控制流语句 4. 生命周期 5. 装饰/样式 总结 前言 Comopse 与 React.Flutter.SwiftUI 同属声明式 UI 框架,有着相同的设计理念和相似的实现原理,但是 Compose 的 API 设计要更加简洁. 本文就这几个框架在代码上做一个对比,感受一下 Compose 超高的代码效率. 1.Stateless 组件 声明式 UI 的基本特点是基于可复用的组件来构建视图,声明式 UI 的开发过程本

  • React Hooks钩子中API的使用示例分析

    目录 hooks是什么 Hooks的作用 使用Hooks组件前后开发模式的对比 Hooks使用策略 为什么要有Hooks useState useEffect使用 useEffect依赖项 使用情景 useMemo使用 useMemo缓存组件方式 useMemo和useEffect的区别 useCallback使用 useContext使用 useRef使用 为什么在函数组件中无法使用ref 如何在类组件中使用ref属性 自定义hooks hooks是什么 hooks理解字面意思就是钩子,是一些

  • 30分钟精通React今年最劲爆的新特性——React Hooks

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? --拥有了Hooks,生命周期钩子函数可以先丢一边了. 你在还在为组件中的this指向而晕头转向吗? --既然Class都丢掉了,哪里还有this?你的人生第一次不再需要面对this. 这样看来,说React Hooks是今年最劲爆的新特性真的毫不夸张.如果你也对react

  • React Hooks的深入理解与使用

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? --拥有了Hooks,生命周期钩子函数可以先丢一边了. 你在还在为组件中的this指向而晕头转向吗? --既然Class都丢掉了,哪里还有this?你的人生第一次不再需要面对this. 这样看来,说React Hooks是今年最劲爆的新特性真的毫不夸张.如果你也对react

  • 利用Jetpack Compose绘制可爱的天气动画

    目录 1. 项目背景 2. MyApp:CuteWeather App界面构成 3. Compose自定义绘制 声明式地创建和使用Canvas 强大的DrawScope 4.简单易用的API 使用原生Canvas 5. 雨天效果 雨滴的绘制 雨滴下落动画 6.Compose自定义布局 7.. 雪天效果 雪花的绘制 雪花飘落动画 雪花的自定义布局 8. 晴天效果 太阳的绘制 太阳的旋转 9. 动画的组合.切换 将图形组合成天气 ComposedIcon ComposedWeather 1. 项目背

  • 记录一次完整的react hooks实践

    写在前面 React在16.8版本正式发布了Hooks.关注了很久,最近正好有一个小需求,赶紧来试一下. 需求描述 需求很简单,部门内部的一个数据查询小工具.大致长成下面这样: 用户首次访问页面,会拉取数据展示.输入筛选条件,点击查询后,会再次拉取数据在前端展示. 需求实现 使用React Class Component的写法 如果使用以前的class写法,简单写一下,代码可能大概长成下面这样: import React from 'react'; import { Tabs, Input, R

  • 基于Webpack4和React hooks搭建项目的方法

    面对日新月异的前端,我表示快学不动了:joy:. Webpack 老早就已经更新到了 V4.x,前段时间 React 又推出了 hooks API.刚好春节在家里休假,时间比较空闲,还是赶紧把 React 技术栈这块补上. 网上有很多介绍 hooks 知识点的文章,但都比较零碎,基本只能写一些小 Demo .还没有比较系统的,全新的基于 hooks 进行搭建实际项目的讲解.所以这里就从开发实际项目的角度,搭建起单页面 Web App 项目的基本脚手架,并基于 hooks API 实现一个 rea

  • 详解如何使用React Hooks请求数据并渲染

    前言 在日常的开发中,从服务器端异步获取数据并渲染是相当高频的操作.在以往使用React Class组件的时候,这种操作我们已经很熟悉了,即在Class组件的componentDidMount中通过ajax来获取数据并setState,触发组件更新. 随着Hook的到来,我们可以在一些场景中使用Hook的写法来替代Class的写法.但是Hook中没有setState.componentDidMount等函数,又如何做到从服务器端异步获取数据并渲染呢?本文将会介绍如何使用React的新特性Hook

  • React Hooks常用场景的使用(小结)

    前言 React 在 v16.8 的版本中推出了 React Hooks 新特性.在我看来,使用 React Hooks 相比于从前的类组件有以下几点好处: 代码可读性更强,原本同一块功能的代码逻辑被拆分在了不同的生命周期函数中,容易使开发者不利于维护和迭代,通过 React Hooks 可以将功能代码聚合,方便阅读维护: 组件树层级变浅,在原本的代码中,我们经常使用 HOC/render props 等方式来复用组件的状态,增强功能等,无疑增加了组件树层数及渲染,而在 React Hooks

随机推荐