Appearance
Props 与 State(数据传递)
React 基础速成
在 React 和 React Native 中,Props 和 State 是两个核心概念,它们用于管理组件的数据和行为。理解这两个概念对于开发 React Native 应用至关重要。
1. Props
Props(properties 的缩写)是组件的输入,它们是从父组件传递给子组件的数据。
基本概念
- 只读性:Props 是只读的,子组件不能修改从父组件接收的 props
- 可传递性:Props 可以从父组件传递到子组件,形成一个 props 链
- 类型多样性:Props 可以是任何类型的数据,包括字符串、数字、布尔值、对象、数组,甚至是函数
使用 Props
传递 Props
jsx
// 父组件
import { View } from 'react-native';
import ChildComponent from './ChildComponent';
export default function ParentComponent() {
return (
<View>
<ChildComponent
name="React Native"
age={30}
isActive={true}
/>
</View>
);
}接收 Props
jsx
// 子组件
import { View, Text } from 'react-native';
const ChildComponent = (props) => {
return (
<View>
<Text>Name: {props.name}</Text>
<Text>Age: {props.age}</Text>
<Text>Is Active: {props.isActive ? 'Yes' : 'No'}</Text>
</View>
);
};
export default ChildComponent;使用解构赋值
jsx
import { View, Text } from 'react-native';
const ChildComponent = ({ name, age, isActive }) => {
return (
<View>
<Text>Name: {name}</Text>
<Text>Age: {age}</Text>
<Text>Is Active: {isActive ? 'Yes' : 'No'}</Text>
</View>
);
};
export default ChildComponent;设置默认值
jsx
import { View, Text } from 'react-native';
const ChildComponent = ({ name = 'Default Name', age = 18, isActive = false }) => {
return (
<View>
<Text>Name: {name}</Text>
<Text>Age: {age}</Text>
<Text>Is Active: {isActive ? 'Yes' : 'No'}</Text>
</View>
);
};
export default ChildComponent;Props 传递函数
Props 不仅可以传递数据,还可以传递函数,这是子组件向父组件通信的主要方式。
jsx
// 父组件
import { View, Text, Button } from 'react-native';
import ChildComponent from './ChildComponent';
import { useState } from 'react';
export default function ParentComponent() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
return (
<View>
<Text>Count: {count}</Text>
<ChildComponent onIncrement={handleIncrement} />
</View>
);
}
// 子组件
import { View, Button } from 'react-native';
const ChildComponent = ({ onIncrement }) => {
return (
<View>
<Button title="Increment" onPress={onIncrement} />
</View>
);
};
export default ChildComponent;2. State
State 是组件内部的状态数据,它用于管理组件的动态变化。
基本概念
- 可变性:State 是可变的,组件可以修改自己的 state
- 私有性:State 是组件私有的,其他组件无法直接访问
- 响应性:当 state 发生变化时,组件会重新渲染
在函数组件中使用 State
在函数组件中,我们使用 useState Hook 来管理 state。
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function Counter() {
// 声明一个名为 count 的 state 变量,初始值为 0
const [count, setCount] = useState(0);
return (
<View>
<Text>Count: {count}</Text>
<Button
title="Increment"
onPress={() => setCount(count + 1)}
/>
<Button
title="Decrement"
onPress={() => setCount(count - 1)}
/>
<Button
title="Reset"
onPress={() => setCount(0)}
/>
</View>
);
}在类组件中使用 State
在类组件中,我们使用 this.state 和 this.setState() 来管理 state。
jsx
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment() {
this.setState({ count: this.state.count + 1 });
}
decrement() {
this.setState({ count: this.state.count - 1 });
}
reset() {
this.setState({ count: 0 });
}
render() {
return (
<View>
<Text>Count: {this.state.count}</Text>
<Button title="Increment" onPress={() => this.increment()} />
<Button title="Decrement" onPress={() => this.decrement()} />
<Button title="Reset" onPress={() => this.reset()} />
</View>
);
}
}
export default Counter;State 的更新
函数式更新
当新的 state 依赖于旧的 state 时,应该使用函数式更新。
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
// 函数式更新
const increment = () => {
setCount(prevCount => prevCount + 1);
};
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={increment} />
</View>
);
}批量更新
React 会批量处理 state 更新,这意味着多个 setState 调用会在一次渲染中完成。
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function User() {
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const updateUser = () => {
// 这两个更新会被批量处理
setName('John');
setAge(30);
};
return (
<View>
<Text>Name: {name}</Text>
<Text>Age: {age}</Text>
<Button title="Update User" onPress={updateUser} />
</View>
);
}3. Props vs State
对比
| 特性 | Props | State |
|---|---|---|
| 来源 | 父组件传递 | 组件内部定义 |
| 可变性 | 只读 | 可变 |
| 影响范围 | 从父组件传递到子组件 | 仅影响当前组件 |
| 初始化 | 在组件调用时设置 | 在组件内部初始化 |
| 更新方式 | 父组件重新传递 | 使用 setState 或 useState |
何时使用 Props
- 当数据需要从父组件传递到子组件时
- 当数据在多个组件之间共享时
- 当数据是静态的或由父组件控制时
何时使用 State
- 当数据需要在组件内部管理时
- 当数据会随着用户交互而变化时
- 当数据只影响当前组件时
4. 状态提升
当多个组件需要共享同一个状态时,我们可以将状态提升到它们的共同父组件中。
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
const ChildComponent1 = ({ count, onIncrement }) => {
return (
<View>
<Text>Child 1 Count: {count}</Text>
<Button title="Increment" onPress={onIncrement} />
</View>
);
};
const ChildComponent2 = ({ count }) => {
return (
<View>
<Text>Child 2 Count: {count}</Text>
</View>
);
};
export default function ParentComponent() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
return (
<View>
<ChildComponent1 count={count} onIncrement={handleIncrement} />
<ChildComponent2 count={count} />
</View>
);
}5. 常见错误与解决方案
错误 1:修改 Props
错误:
jsx
import { View, Text, Button } from 'react-native';
const ChildComponent = (props) => {
const updateName = () => {
props.name = 'New Name'; // 错误:不能修改 props
};
return (
<View>
<Text>Name: {props.name}</Text>
<Button title="Update Name" onPress={updateName} />
</View>
);
};
export default ChildComponent;解决方案:
jsx
import { View, Text, Button } from 'react-native';
const ChildComponent = ({ name, onUpdateName }) => {
const updateName = () => {
onUpdateName('New Name'); // 正确:通过回调函数通知父组件
};
return (
<View>
<Text>Name: {name}</Text>
<Button title="Update Name" onPress={updateName} />
</View>
);
};
export default ChildComponent;错误 2:直接修改 State
错误:
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
count++; // 错误:不能直接修改 state
setCount(count);
};
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={increment} />
</View>
);
}解决方案:
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1); // 正确:使用 setCount 更新 state
};
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={increment} />
</View>
);
}错误 3:在渲染过程中更新 State
错误:
jsx
import { View, Text } from 'react-native';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
// 错误:在渲染过程中更新 state
setCount(count + 1);
return (
<View>
<Text>Count: {count}</Text>
</View>
);
}解决方案:
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1); // 正确:在事件处理函数中更新 state
};
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={increment} />
</View>
);
}6. 最佳实践
1. 保持 State 最小化
- 只在 state 中存储必要的数据
- 避免在 state 中存储可以通过计算得到的值
- 考虑使用 useMemo 或 useCallback 优化计算
2. 状态管理策略
- 对于简单的状态,使用 useState
- 对于复杂的状态,考虑使用 useReducer 或状态管理库(如 Redux)
- 对于跨组件共享的状态,使用 Context API 或状态管理库
3. Props 传递
- 避免过度传递 props(prop drilling)
- 对于深层嵌套的组件,考虑使用 Context API
- 使用 TypeScript 或 PropTypes 来验证 props 类型
4. 性能优化
- 使用 useCallback 缓存函数
- 使用 useMemo 缓存计算结果
- 对于大型列表,使用 React.memo 避免不必要的重新渲染
7. 总结
Props 和 State 是 React 和 React Native 中管理数据的核心概念:
- Props:从父组件传递给子组件的数据,只读
- State:组件内部管理的数据,可变
理解并正确使用 Props 和 State,是构建高质量 React Native 应用的关键。通过合理的状态管理和 props 传递,你可以创建出结构清晰、易于维护的应用。
下一节,我们将学习条件渲染和列表渲染,这是 React 中常用的渲染技术。
