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)

相关推荐

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

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

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

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

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

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

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

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

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

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

  • 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单词的时候 应该就大概知道 这是一个关于导航

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

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

  • 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

  • 记录一次完整的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类组件相比,React函数式组件究竟有何不同? 一般的回答都是: 类组件比函数式组件多了更多的特性,比如 state,那如果有 Hooks 之后呢? 函数组件性能比类组件好,但是在现代浏览器中,闭包和类的原始性能只有在极端场景下才会有明显的差别. 性能主要取决于代码的作用,而不是选择函数式还是类组件.尽管优化策略有差别,但性能差异可以忽略不计. 参考官网:(https://zh-hans.reactjs.org/docs/hooks-faq.html#are-hooks-slow-b

  • 如何对react hooks进行单元测试的方法

    写在前面 使用 react hook 来做公司的新项目有一段时间了,大大小小的坑踩了不少.由于是公司项目,因此必须要编写单元测试来确保业务逻辑的正确性以及重构时代码的可维护性与稳定性,之前的项目使用的是 react@15.x 的版本,使用 enzyme 配合 jest 来做单元测试毫无压力,但新项目使用的是 react@16.8 ,编写单元测试的时候,遇到不少阻碍,因此总结此篇文章算作心得分享出来. 配合 enzyme 来进行测试 首先,enzyme 对于 hook 的支持程度,可以参考这个 i

  • C#实现的字符串相似度对比类

    本类适用于比较2个字符的相似度,代码如下: using System; using System.Collections.Generic; using System.Text; public class StringCompute { #region 私有变量 /// <summary> /// 字符串1 /// </summary> private char[] _ArrChar1; /// <summary> /// 字符串2 /// </summary>

  • react的hooks的用法详解

    hooks的作用 它改变了原始的React类的开发方式,改用了函数形式;它改变了复杂的状态操作形式,让程序员用起来更轻松;它改变了一个状态组件的复用性,让组件的复用性大大增加. useState // 声明状态 const [ count , setCount ] = useState(0); // 使用状态 <p>You clicked {count} times</p> <button onClick={()=>{setCount(count+1)}}>cli

  • 15 分钟掌握vue-next函数式api(小结)

    写在前面 在分享 vue-next 各个子模块的实现之前,我觉的有必要比较全面的整理下 vue-next 中提出的函数式 api,了解这些的话,无论是对于源码的阅读,还是当正式版发布时开始学习,应该都会有起到一定的辅助作用. 类似的东西在网上有很多,只是会比较零碎,同时有些也相对过时了,当然当前整理的这些也有可能会过时,毕竟代码还处于 pre-alpha 的阶段,但其中的设计思想应该是不会改变了. 往期文章 15 分钟掌握 vue-next 响应式原理 vue-next/runtime-core

随机推荐

其他