Jetpack?Compose對比React?Hooks?API相似度

眾所周知Jetpack Compose設(shè)計理念甚至團隊成員很多都來自React,在API方面參考了很多React(Hooks) 的設(shè)計,通過與React進行對比可以更好地熟悉Compose的相關(guān)功能。
Compose目前處于alpha版,雖然API還會調(diào)整,但是從功能上已經(jīng)基本對齊了React,不會有大變化,本文基于1.0.0-alpha11。
React Component vs Composable
React中Component成為分割UI的基本單元,特別是16.8之后Hooks引入的函數(shù)組件,相對于類組件更利于UI與邏輯解耦。函數(shù)組件是一個接受Props作為參數(shù)并返回JSX node的函數(shù):
function Greeting(props) {
return <span>Hello {props.name}!</span>;
}
Compose同樣使用函數(shù)作為組件:添加了@Composable注解的函數(shù)。而且借助Kotlin的DSL實現(xiàn)聲明式語法,而無需額外引入JSX等其他標記語言,相對于React更加簡潔:
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
JSX vs DSL
DSL相對于JSX更加簡潔,可以直接使用原生語法表示各種邏輯。
loop
例如在JSX中實現(xiàn)一個循環(huán)邏輯,需要兩種語言混編
function NumberList(props) {
return (
<ul>
{props.numbers.map((number) => (
<ListItem value={number} />
))}
</ul>
);
}
DSL中的循環(huán)就是普通的for循環(huán)
@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都使用函數(shù)組件創(chuàng)建UI,區(qū)別在于一個使用DSL,另一個依靠JSX。
React中,子組件通過props的children字段傳入
function Container(props) {
return <div>{props.children}</div>;
}
<Container>
<span>Hello world!</span>
</Container>;
Compose中,子組件以@Composable函數(shù)的形式傳入
@Composable
fun Container(children: @Composable () -> Unit) {
Box {
children()
}
}
Container {
Text("Hello world"!)
}
Context vs Ambient(CompositionLocal)
對于函數(shù)組件來說,建議使用props/parameter傳遞數(shù)據(jù),但是允許一些全局數(shù)據(jù)在組件間共享。React使用Context存放全局數(shù)據(jù),Compose使用Ambient(alpha12中已改名CompositionLocal)存放全局數(shù)據(jù)
createContext : ambientOf
React使用createContext創(chuàng)建Context:
const MyContext = React.createContext(defaultValue);
Compose使用ambientOf創(chuàng)建Ambient:
val myValue = ambientOf<MyAmbient>()
Provider : Provider
React和Compose中都使用Provider注入全局數(shù)據(jù),供子組件訪問
<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,狀態(tài)管理都是至關(guān)重要的。
React使用useState hook創(chuàng)建State
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1)}>
You clicked {count} times
</button>
Compose使用mutableStateOf創(chuàng)建一個state,還可以通過by代理的方式獲取
val count = remember { mutableStateOf(0) }
Button(onClick = { count.value++ }) {
Text("You clicked ${count.value} times")
}
還可以通過解構(gòu)分別獲取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創(chuàng)建state時往往會remeber{ } 避免重繪時的反復(fù)創(chuàng)建state,相當于useMemo
useMemo vs remember
React使用useMemo hook用來保存那些不能隨重繪反復(fù)計算的值,只有參數(shù)變化時才會重新計算。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Compose中同樣功能使用remember實現(xiàn),同樣通過參數(shù)作為重新計算的判斷條件
val memoizedValue = remember(a, b) { computeExpensiveValue(a, b) }
useEffect vs SideEffect
函數(shù)組件滿足純函數(shù)的要求:無副作用、無狀態(tài)、即使多次運行也不會產(chǎn)生影響。但是總有一些邏輯不能以純函數(shù)執(zhí)行,例如 生命周期回調(diào)、日志、訂閱、計時等,只能在特定時機執(zhí)行,不能像一個純函數(shù)那樣可以執(zhí)行多次而不產(chǎn)生副作用。
React中,useEffect 提供一個hook點,會在每次render時執(zhí)行。注意 這不同于直接寫在外面,當diff沒有變化時不需要重新render,就不需要執(zhí)行useEffect了
useEffect(() => {
sideEffectRunEveryRender();
});
Compose中使用SideEffect處理副作用(早期版本是onCommit{ })
SideEffect {
sideEffectRunEveryComposition()
}
useEffect(callback, deps) :DisposableEffect
跟useMemo一樣可以接受參數(shù),每次render時,只有當參數(shù)變化時才執(zhí)行:
useEffect(() => {
sideEffect();
}, [dep1, dep2]);
只在第一次render時執(zhí)行的邏輯(相當于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封裝可復(fù)用邏輯。Hooks可以調(diào)用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函數(shù)即可被用來實現(xiàn)一段可復(fù)用的處理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相似度的詳細內(nèi)容,更多關(guān)于Jetpack Compose對比React的資料請關(guān)注腳本之家其它相關(guān)文章!
- vue2 d3實現(xiàn)企查查股權(quán)穿透圖股權(quán)結(jié)構(gòu)圖效果詳解
- React?Hooks使用startTransition與useTransition教程示例
- 解決React報錯Rendered more hooks than during the previous render
- react?hooks?UI與業(yè)務(wù)邏輯分離必要性技術(shù)方案
- React?Hooks之usePolymerAction抽象代碼結(jié)構(gòu)設(shè)計理念
- React?Hooks useReducer?逃避deps組件渲染次數(shù)增加陷阱
- React函數(shù)組件useContext useReducer自定義hooks
- react?hooks?d3實現(xiàn)企查查股權(quán)穿透圖結(jié)構(gòu)圖效果詳解
相關(guān)文章
Android通過ExifInterface判斷Camera圖片方向的方法
今天小編就為大家分享一篇關(guān)于Android通過ExifInterface判斷相機圖片朝向的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12
Android RecyclerView實現(xiàn)多種item布局的方法
本篇文章主要介紹了Android RecyclerView實現(xiàn)多種item布局的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
Android下拉刷新控件PullToRefresh實例解析
這篇文章主要為大家詳細解析了Android下拉刷新控件PullToRefresh實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09
Android 中IntentFilter的匹配規(guī)則實例詳解
這篇文章主要介紹了Android 中IntentFilter的匹配規(guī)則實例詳解的相關(guān)資料,希望通過本文大家能了解掌握IntentFilter的匹配規(guī)則問題,需要的朋友可以參考下2017-09-09
Android PopupWindow實現(xiàn)微信右上角的彈出菜單
這篇文章主要為大家詳細介紹了Android PopupWindow實現(xiàn)微信右上角的彈出菜單,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-04-04

