组件
本文由 AI 协助更新
组件负责渲染。本文介绍组件与元素、Props、State、单向数据流等基本概念。
认识组件和元素
组件是一个特殊的函数,它返回 null 或元素。
function TodoItem() {
return <Text>买菜</Text>
}
如上,TodoItem 就是一个组件,Text 也是一个组件,用于渲染文本。
什么是元素呢?
<Text>买菜</Text> 就是一个元素。
这种把组件包裹在一对尖括号的语法称为 JSX,它是一种语法糖。
const element = <Text>买菜</Text>
上面这行代码最终被 Babel 编译为:
const element = React.createElement(Text, null, '买菜')
可以自己试试看。
createElement 接受三个参数,第一个指定要渲染的组件,第二个指定组件的属性,第三个参数指定子元素
一些注意事项:
组件函数名以大写字母开头
组件返回
null,代表什么也不渲染
认识 Props
在下面这个例子中,TodoItem 组件渲染的文本是被写死的:
function TodoItem() {
return <Text>买菜</Text>
}
如何动态改变呢?我们通过定义属性(Props)来解决。
interface TodoItemProps {
title: string
}
function TodoItem(props: TodoItemProps) {
return <Text>{props.title}</Text>
}
function App() {
return (
<View>
<TodoItem title="买菜" />
<TodoItem title="写代码" />
<TodoItem title="运动" />
</View>
)
}
title 是 TodoItem 组件的属性,我们在 App 组件中为 title 属性赋值。
这样,title 就没有写死在 TodoItem 组件中,而是由使用它的组件来决定。
认识 State
上面这个例子还是不够动态,title 属性虽然没有写死在 TodoItem 中,但是却写死在 App 中。有没有更动态的方法呢?
在这里,我们使用状态:
import React, { useState } from 'react'
import { View, Text, TextInput, Button, StyleSheet } from 'react-native'
interface TodoItemProps {
title: string
}
function TodoItem(props: TodoItemProps) {
return <Text style={styles.todoText}>{props.title}</Text>
}
function App() {
const [currentTodo, setCurrentTodo] = useState('')
const [inputText, setInputText] = useState('')
return (
<View style={styles.container}>
<TodoItem title={currentTodo || '请输入待办事项'} />
<TextInput
value={inputText}
onChangeText={setInputText}
placeholder="输入待办事项"
style={styles.input}
/>
<Button title="添加" onPress={() => setCurrentTodo(inputText)} />
</View>
)
}
我们从 react 导入 useState,用 const [currentTodo, setCurrentTodo] = useState('') 得到当前值和更新函数;setCurrentTodo 被调用后组件会重新渲染,新的 currentTodo 会传给 TodoItem 的 title。像这样由 useState 创建的变量称为状态 (State)。变量名可自定,setter 引用稳定,可安全传给子组件或放入依赖数组。
State vs Props
状态是由组件内部自己维护的,是可变的。
属性是由组件外部传递进来的,是不可变的。
❗ 如果属性是一个对象,注意不要改变这个对象的属性,不可变只是规则,是需要我们自觉维护的。
状态或属性发生变化,将导致 UI 发生变化,我们通过改变数据来改变 UI。数据变了,UI 也就变了。
数据驱动视图。
单向数据流
用 useState 创建 inputText / setInputText,把 inputText 赋给 TextInput 的 value,把 setInputText 赋给 onChangeText:显示什么、输入时做什么都由父组件 App 决定,这就是受控组件。数据从父流向子,不能反向,即单向数据流。
若在 onChangeText 里对输入做处理再 setInputText,例如过滤数字:
<TextInput
value={inputText}
onChangeText={(value) => setInputText(value.replace(/[0-9]/g, ''))}
placeholder="输入待办事项"
style={styles.input}
/>
在上面的代码中,我们把用户输入中的所有数字都过滤掉,再作为参数传递给 setInputText。
setInputText 被调用后,inputText 就会发生变化,而 inputText 刚好被赋值给了 TextInput 的属性 value,然后用户看到的输入就是没有数字的文本。
自定义组件应尽量受控。点击「添加」时用 onPress={() => setCurrentTodo(inputText)} 把输入同步到状态,界面随之更新。