本文将从 iOS 开发者的视角,系统地介绍 React(Native)中的各种变量和参数形式,并通过完整示例演示 props(参数) 与 回调 的定义及使用。
1. React 中的变量与参数分类(与 iOS 类比)
在开始编写组件之前,先明确 React 中几种常见的“数据载体”及其作用范围:
| 分类 | React 中的体现 | 类比 iOS (UIKit/Swift) | 作用范围 |
|---|---|---|---|
| 全局参数 | Context、Redux store、全局模块变量 |
UIApplication.shared.delegate 或全局单例 |
整个应用,任意组件可访问 |
| 局部变量 | 组件函数内的 let / const 变量 |
方法内部定义的局部变量 | 仅当前函数/代码块内 |
| 参数 (props) | 父组件传递给子组件的 props
|
初始化参数(init 参数)或 @property 属性 |
子组件内部(只读) |
| 内部状态 (state) |
useState 或 this.state
|
视图控制器的私有属性(private var) |
当前组件内部,变化会触发重渲染 |
1.1 全局参数
React 中没有内置的“全局变量”,但可以通过以下方式实现跨组件共享数据:
-
Context:类似 iOS 中的
UIApplication.shared或依赖注入,避免 props 逐层传递(props drilling)。 - 状态管理库(如 Redux、Zustand):类似 iOS 中的单向数据流框架(ReSwift)或 Combine 的全局 Store。
-
模块级变量:在 JS 文件中
export一个变量,但要注意它不是响应式的(变化不会触发 UI 更新)。
// 全局模块变量(简单但不响应式)
export const appVersion = '1.0.0';
// Context 示例(响应式全局数据)
const UserContext = React.createContext(null);
// 顶层提供
<UserContext.Provider value={{ name: 'GlobalUser' }}>
<App />
</UserContext.Provider>
// 任意子组件消费
const user = useContext(UserContext);
1.2 局部变量
在组件函数体内直接定义的变量,每次渲染都会重新计算,改变它不会触发重新渲染。
const MyComponent = () => {
let counter = 0; // 局部变量
const handlePress = () => {
counter++; // 不会触发 UI 更新
console.log(counter);
};
return <Button onPress={handlePress} />;
};
若需要变化时更新 UI,应使用 state(见下文)。
1.3 参数(props)—— 本节重点
父组件向子组件传递数据的主要方式,只读。下文将详细说明。
1.4 内部状态(state)
组件内部的可变数据,变化时组件会重新渲染。类似 iOS 中 @Published 属性或手动调用 setNeedsDisplay()。
const [count, setCount] = useState(0);
// 更新会触发重新渲染
setCount(count + 1);
2. 参数(props)的定义及使用形式
在 React(Native)中,父组件向子组件传递数据主要通过 props。
-
定义位置:在子组件的函数参数中定义(或类组件的
this.props)。 -
类型与默认值:推荐使用
propTypes和defaultProps进行类型检查与默认值设置(类似 OC 中的属性声明与初始化)。 -
使用方式:父组件像 HTML 标签属性一样为子组件传递值,子组件通过解构或直接访问
props来使用。
定义形式(子组件侧)
// 方式1:函数组件 + 解构参数(最常用)
const UserCard = ({ name, onLike }) => { ... };
// 方式2:显式使用 props 对象
const UserCard = (props) => {
const { name, onLike } = props;
...
};
// 类型与默认值(可选但推荐)
UserCard.propTypes = {
name: PropTypes.string.isRequired, // 必传字符串
onLike: PropTypes.func, // 可选函数
};
UserCard.defaultProps = {
onLike: () => {}, // 默认空函数
};
使用形式(父组件侧)
// 直接传递字面量或变量
<UserCard name="张三" onLike={handleLike} />
// 传递动态值(如 state 中的值)
<UserCard name={user.name} onLike={handleLike} />
与 iOS 的类比:
name类似于@property (nonatomic, copy) NSString *name;,在初始化时赋值。onLike类似于@property (nonatomic, copy) void (^onLikeBlock)(NSString *name);或 delegate 方法。propTypes相当于编译时的类型检查(类似 Swift 的类型系统),defaultProps相当于 OC 中init方法里给属性赋默认值。
3. 完整示例:用户列表与点赞功能
3.1 子组件:UserCard
// UserCard.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
const UserCard = ({ name, onLike }) => {
// 内部处理点击事件
const handlePress = () => {
// 调用父组件传入的回调,并把当前用户的名字传回去
if (onLike) {
onLike(name);
}
};
return (
<View style={styles.card}>
<Text style={styles.name}>{name}</Text>
<Button title="喜欢" onPress={handlePress} />
</View>
);
};
// 定义 props 的类型和默认值(类似 OC 中的参数校验)
UserCard.propTypes = {
name: PropTypes.string.isRequired, // name 是字符串,必传
onLike: PropTypes.func, // onLike 是函数,可选
};
UserCard.defaultProps = {
onLike: () => {}, // 默认空函数,避免回调未定义时报错
};
const styles = StyleSheet.create({
card: {
padding: 12,
margin: 8,
backgroundColor: '#f0f0f0',
borderRadius: 8,
},
name: {
fontSize: 18,
marginBottom: 8,
},
});
export default UserCard;
3.2 父组件:App
// App.js
import React, { useState } from 'react';
import { View, FlatList, Alert, StyleSheet } from 'react-native';
import UserCard from './UserCard';
const App = () => {
// 定义状态:用户列表(每个用户包含 id 和 name)
const [users, setUsers] = useState([
{ id: '1', name: '张三' },
{ id: '2', name: '李四' },
{ id: '3', name: '王五' },
]);
// 定义回调函数:处理点赞逻辑
const handleLike = (likedName) => {
Alert.alert(`你点赞了 ${likedName}`);
// 实际开发中可能更新服务端或修改本地状态
console.log(`点赞用户:${likedName}`);
};
return (
<View style={styles.container}>
<FlatList
data={users}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
// 传递 name 参数 和 onLike 回调
<UserCard name={item.name} onLike={handleLike} />
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 40,
},
});
export default App;
4. 关键点解释
4.1 参数(props)的传递与使用
-
定义:子组件
UserCard的函数参数({ name, onLike })解构了父组件传入的 props。 -
传递:父组件中使用
<UserCard name={item.name} onLike={handleLike} />。 -
类型约束:
propTypes类似 OC 中的参数类型检查,defaultProps提供默认值(避免回调为undefined)。
4.2 回调的定义与使用
-
定义:父组件声明
handleLike函数,接收子组件传回的数据likedName。 -
传递:通过
onLike={handleLike}将函数作为 props 传给子组件。 -
调用:子组件在
handlePress中调用onLike(name),触发父组件逻辑。
4.3 数据流方向
- 单向数据流:父组件 → 子组件(通过 props);子组件 → 父组件(通过回调函数传递数据)。这与 iOS 中 delegate / block 的思想完全一致。
5. 与 iOS 开发的类比
| iOS (UIKit) | React Native |
|---|---|
@property (nonatomic, copy) NSString *name; |
name 作为 props 传入 |
定义一个 delegate 协议,包含 - (void)didLikeUser:(NSString *)name;
|
父组件定义 handleLike 函数,作为 onLike 传递 |
子组件 [self.delegate didLikeUser:self.name];
|
子组件调用 onLike(name)
|
父组件设置 card.delegate = self;
|
父组件使用 <UserCard onLike={handleLike} />
|
6. 常见变体
6.1 带参数的回调(传递多个值)
// 子组件
const handlePress = () => {
onLike({ userName: name, timestamp: Date.now() });
};
// 父组件
const handleLike = (info) => {
console.log(info.userName, info.timestamp);
};
6.2 可选回调与条件调用
const handlePress = () => {
onLike && onLike(name); // 安全调用,类似 OC 中 `if ([self.delegate respondsToSelector:...])`
};
6.3 类组件中的回调(兼容老代码)
class UserCard extends React.Component {
handlePress = () => {
this.props.onLike(this.props.name);
};
render() { /* ... */ }
}
7. 注意事项(对 iOS 开发者的提醒)
- props 是只读的:子组件永远不能修改自己的 props,只能通过回调通知父组件去修改(类似于 Cocoa 中的“视图不直接修改模型,而是通过控制器”)。
- 状态提升:如果多个组件需要共享同一份数据或回调,把数据/回调定义在它们的共同父组件中,再通过 props 下传(类似于在 ViewController 中管理数据,传递给多个子 View)。
-
区分局部变量与 state:局部变量的改变不会触发 UI 更新;若需要响应式更新,请使用
useState。 - 全局参数的谨慎使用:过多的全局状态会让数据流难以追踪。优先考虑 props 和状态提升,必要时使用 Context 或 Redux。
-
避免过早优化:不需要像 iOS 中那样担心循环引用(React 的函数式组件 + hooks 已处理),但回调函数若依赖外部 props/state,注意使用
useCallback避免不必要的重新渲染。