RN 参数变量、回调的定义及使用

本文将从 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) useStatethis.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)。
  • 类型与默认值:推荐使用 propTypesdefaultProps 进行类型检查与默认值设置(类似 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 开发者的提醒)

  1. props 是只读的:子组件永远不能修改自己的 props,只能通过回调通知父组件去修改(类似于 Cocoa 中的“视图不直接修改模型,而是通过控制器”)。
  2. 状态提升:如果多个组件需要共享同一份数据或回调,把数据/回调定义在它们的共同父组件中,再通过 props 下传(类似于在 ViewController 中管理数据,传递给多个子 View)。
  3. 区分局部变量与 state:局部变量的改变不会触发 UI 更新;若需要响应式更新,请使用 useState
  4. 全局参数的谨慎使用:过多的全局状态会让数据流难以追踪。优先考虑 props 和状态提升,必要时使用 Context 或 Redux。
  5. 避免过早优化:不需要像 iOS 中那样担心循环引用(React 的函数式组件 + hooks 已处理),但回调函数若依赖外部 props/state,注意使用 useCallback 避免不必要的重新渲染。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容