[Android翻译]React到Jetpack Compose词典

1,205 阅读5分钟

原文地址:tigeroakes.com/posts/react…

原文作者:tigeroakes.com/

发布时间:2020年7月20日

我在一个个人项目上试用了Jetpack Compose,很喜欢这个API。Compose是一个相当大的API转变,我发现我的React知识比我的Android知识更有帮助。也许这就是React Native开发者来取代原生Android开发者的原因。

两个库中的许多概念和函数工作原理相同,但名称不同。下面是我看到的术语以及解释的汇编。Jetpack Compose还在变化,这个列表是基于0.1.0-dev14版本的。

子元素Prop > 子元素Composable

React和Compose都将要显示在另一个UI组件中的元素称为子元素。

React在一个名为children的特殊道具下,通过值来传递子元素。

function Container(props) {
  return <div>{props.children}</div>;
}

<Container>
  <span>Hello world!</span>
</Container>

Jetpack Compose 传递可合成函数,因为函数本身不返回任何东西。

@Composable
fun Container(children: @Composable () -> Unit) {
  Box {
    children()
  }
}

Container {
  Text("Hello world"!)
}

语境 > 环境

虽然大多数数据都是通过组件树作为道具/参数传递的,但有时这种模式可能会很麻烦。React包含Context API来共享这些数据。Compose使用Ambient来完成同样的事情。

createContext > ambientOf

一个React Context是用React.createContext创建的,而Jetpack Compose ambient是用ambientOf创建的。

Provider > Provider

ReactCompose中都可以使用 "Provider "来控制值。

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

useContext > Ambient.current

访问React上下文值是使用useContext钩子完成的。

const myValue = useContext(MyContext);

访问一个Ambient的值是通过使用.current getter来完成的。

val myValue = MyAmbient.current

useEffect > onCommit

突变、订阅、定时器、日志和其他副作用都不允许放在UI组件的主体内。它们必须放在一个回调函数里面,React和Jetpack Compose都会在正确的点上调用。

React有一个useEffect钩子,可以在每次渲染时运行副作用。

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

Compose有onCommit效果,可以在每次构图时运行侧效果。

onCommit {
  sideEffectRunEveryComposition()
}

清理函数 > onDispose

副作用经常会产生资源,一旦UI组件未被使用,就需要清理。React允许useEffect函数返回第二个函数,即清理函数

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

Jetpack Compose在onCommit中公开了一个onDispose函数,它在效果离开合成时运行。

onCommit {
  val subscription = source.subscribe()
  onDispose {
    subscription.unsubscribe()
  }
}

useEffect(callback, deps) > onCommit(input, callback)

useEffectonCommit都默认在每次渲染/合成后运行。然而,副作用也可以只在其依赖关系发生变化时运行。

React允许向useEffect传递第二个参数,并附上依赖关系列表:

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

Jetpack Compose允许在回调前将输入作为参数传递:

onCommit(input1, input2) {
  sideEffect()
}

useEffect(callback, []) > onActive(callback)

副作用也可以只在UI组件首次显示时运行。

当一个空的依赖列表被传递给useEffect时,副作用只运行一次。

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

Jetpack Compose有一个单独的onActive效果

onActive {
  sideEffectOnActive()
}

钩子 > 效果

React让你可以构建自己的钩子,将组件逻辑提取到可重用的函数中。它们可以使用其他钩子,如useStateuseEffect来封装与组件生命周期相关的逻辑。

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;
}

在Jetpack Compose中,@Composable函数被用作相当于钩子的功能(同时也是相当于组件的功能)。这些可组合函数,有时也被称为 "效果 "函数,通常以小写字母而不是大写字母开头。

@Composable
fun friendStatus(friendID: String): State<Boolean?> {
  val isOnline = state<Boolean?> { null }

  onCommit {
    val handleStatusChange = { status: FriendStatus ->
      isOnline.value = status.isOnline
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange)
    onDispose {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange)
    }
  }

  return isOnline
}

关键字Prop > 关键字Composable

关键字是用来帮助React和Jetpack Compose识别哪些项目发生了变化、被添加或被删除。它们必须在你在UI组件中显示的项目列表中是唯一的。

React有一个名为key的特殊字符串道具

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

Jetpack Compose有一个特殊的实用工具,叫做key,可以接受任何输入。

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

在Compose中可以将多个输入传入key,而React只需要一个字符串(虽然可以将多个字符串连在一起)。

.map > For Loop

由于React通过值来传递元素,所以通常使用array.map()来创建对应于数组的元素。map回调中返回的元素可以嵌入到JSX中

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

在Jetpack Compose中的可组合UI函数会发出其他UI可组合函数,并且不返回任何东西。因此,可以使用一个简单的for循环来代替.map()

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

事实上,可以使用任何迭代方法,如.forEach()

useMemo > remember

React允许只有在组件内部的某些依赖关系发生变化时,才会通过useMemo钩子重新计算值。

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

Jetpack Compose有一个类似的函数,名为remember,它只在输入改变时重新计算一个值。

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

React组件 > Composable

在React中,组件用于将UI分割成独立的、可重用的部分。它们可以采用函数的形式,接受一个props参数并返回一个React节点。

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

在Jetpack Compose中,Composable函数是用于将用户界面分割成独立的、可重复使用的构件。它们是带有 @Composable 注释的函数,可以接受任何数量的参数。

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

这两个库也将这些概念称为UI组件。然而,Jetpack Compose也使用可合成函数来实现其他功能,请看hook > effectkey的例子。

渲染 > 合成

一旦UI组件内部的数据发生了变化,库必须调整在屏幕上呈现的内容。React将其称为渲染,而Jetpack Compose将其称为合成。

调和器 > 合成器

在内部,React需要弄清楚当一个组件被渲染时有什么变化。这个差异的算法叫做 "Reconciler"。React Fiber指的是新的Fiber Reconciler的发布,它取代了旧的算法。

Jetpack Compose的diffing是用Composer完成的。它决定了每次composable完成组成时节点的变化。

状态 > 状态

React和Compose都将你要突变的本地变量称为 "state"。

useState > state

在React中创建一个新的状态变量是通过useState钩子完成的。它返回一个包含值和setter的元组。

const [count, setCount] = useState(0);

<button onClick={() => setCount(count + 1)}>
  You clicked {count} times
</button>

Compose使用state函数返回一个MutableState对象,其中包含一个带有getter和setter的变量。

val count = state { 0 }

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

Storybook > 预览

Storybook工具可以帮助你通过创建 "故事 "在网络上独立预览React组件。Jetpack Compose中的@Preview注解可以让你构建可以在Android Studio中预览的可组合示例。

三元操作符 > If语句

React组件经常使用三元运算符(cond ? a : b)来有条件地渲染组件,因为成功的分支会被返回(与JavaScript中的if语句不同)。

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

Kotlin没有三元运算符,因为if语句确实会返回成功分支的结果。由于Kotlin中的if语句就像JavaScript中的三元操作符一样,所以不需要第二个变体。

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

通过( www.DeepL.com/Translator )(免费版)翻译