Appearance
Hooks 基础(useState / useEffect)
React 基础速成
Hooks 是 React 16.8 引入的新特性,它允许我们在函数组件中使用状态和其他 React 特性。在 React Native 中,Hooks 已经成为管理状态和副作用的标准方式。
1. 什么是 Hooks?
Hooks 是一些特殊的函数,它们允许你在函数组件中使用 React 的状态和生命周期特性。
为什么使用 Hooks?
- 函数组件更简洁:Hooks 允许我们使用函数组件而不是类组件
- 逻辑复用:Hooks 使我们能够在不同组件之间复用状态逻辑
- 更好的代码组织:Hooks 允许我们按功能组织代码,而不是按生命周期方法
- 更容易理解:Hooks 使代码更线性,更容易理解
2. useState Hook
useState 是最基本的 Hook,它允许我们在函数组件中管理状态。
基本语法
jsx
import { useState } from 'react';
function Counter() {
// 声明一个名为 count 的状态变量,初始值为 0
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}在 React Native 中的使用:
jsx
import { View, Text, Button } from 'react-native';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<View>
<Text>You clicked {count} times</Text>
<Button
title="Click me"
onPress={() => setCount(count + 1)}
/>
</View>
);
}状态更新
基本更新
jsx
const [count, setCount] = useState(0);
// 基本更新
setCount(count + 1);函数式更新
当新的状态依赖于旧的状态时,应该使用函数式更新:
jsx
const [count, setCount] = useState(0);
// 函数式更新
setCount(prevCount => prevCount + 1);批量更新
React 会批量处理状态更新,这意味着多个 setState 调用会在一次渲染中完成:
jsx
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const updateUser = () => {
// 这两个更新会被批量处理
setName('John');
setAge(30);
};3. useEffect Hook
useEffect 是另一个常用的 Hook,它允许我们在函数组件中执行副作用操作。
基本语法
jsx
import { useEffect } from 'react';
function Example() {
useEffect(() => {
// 副作用代码
console.log('Component mounted');
// 清理函数
return () => {
console.log('Component unmounted');
};
}, []); // 依赖数组
return <div>Example</div>;
}在 React Native 中的使用:
jsx
import { View, Text } from 'react-native';
import { useEffect } from 'react';
export default function Example() {
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component unmounted');
};
}, []);
return (
<View>
<Text>Example</Text>
</View>
);
}依赖数组
useEffect 接受第二个参数,一个依赖数组,用于控制副作用的执行时机:
空依赖数组
当依赖数组为空时,副作用只会在组件挂载时执行一次:
jsx
useEffect(() => {
// 只在组件挂载时执行
console.log('Component mounted');
}, []);依赖项
当依赖数组包含值时,副作用会在依赖项变化时执行:
jsx
const [count, setCount] = useState(0);
useEffect(() => {
// 当 count 变化时执行
console.log(`Count changed to: ${count}`);
}, [count]);没有依赖数组
当没有依赖数组时,副作用会在每次渲染后执行:
jsx
useEffect(() => {
// 在每次渲染后执行
console.log('Component re-rendered');
});4. 自定义 Hook
我们可以创建自己的自定义 Hook 来复用状态逻辑。
基本语法
jsx
import { useState, useEffect } from 'react';
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => {
setCount(prevCount => prevCount + 1);
};
const decrement = () => {
setCount(prevCount => prevCount - 1);
};
const reset = () => {
setCount(initialValue);
};
return { count, increment, decrement, reset };
}
// 使用自定义 Hook
function Counter() {
const { count, increment, decrement, reset } = useCounter(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
);
}在 React Native 中的使用:
jsx
import { View, Text, Button } from 'react-native';
import { useState, useEffect } from 'react';
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => {
setCount(prevCount => prevCount + 1);
};
const decrement = () => {
setCount(prevCount => prevCount - 1);
};
const reset = () => {
setCount(initialValue);
};
return { count, increment, decrement, reset };
}
export default function Counter() {
const { count, increment, decrement, reset } = useCounter(0);
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={increment} />
<Button title="Decrement" onPress={decrement} />
<Button title="Reset" onPress={reset} />
</View>
);
}5. 常见错误与解决方案
错误 1:在条件语句中使用 Hook
错误:
jsx
import { useState } from 'react';
function Counter() {
if (true) {
const [count, setCount] = useState(0); // 错误:在条件语句中使用 Hook
}
return (
<div>
<p>Count: {count}</p>
</div>
);
}解决方案:
jsx
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // 正确:在组件顶部使用 Hook
return (
<div>
<p>Count: {count}</p>
</div>
);
}错误 2:在循环中使用 Hook
错误:
jsx
import { useState } from 'react';
function Counter() {
for (let i = 0; i < 5; i++) {
const [count, setCount] = useState(0); // 错误:在循环中使用 Hook
}
return (
<div>
<p>Count: {count}</p>
</div>
);
}解决方案:
jsx
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // 正确:在组件顶部使用 Hook
return (
<div>
<p>Count: {count}</p>
</div>
);
}错误 3:在嵌套函数中使用 Hook
错误:
jsx
import { useState } from 'react';
function Counter() {
function innerFunction() {
const [count, setCount] = useState(0); // 错误:在嵌套函数中使用 Hook
}
innerFunction();
return (
<div>
<p>Count: {count}</p>
</div>
);
}解决方案:
jsx
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // 正确:在组件顶部使用 Hook
function innerFunction() {
// 可以使用 count 和 setCount
}
innerFunction();
return (
<div>
<p>Count: {count}</p>
</div>
);
}6. 最佳实践
1. 只在需要时使用 Hook
- 只在函数组件的顶部使用 Hook
- 不要在条件语句、循环或嵌套函数中使用 Hook
- 确保 Hook 的调用顺序在每次渲染中保持一致
2. 合理使用依赖数组
- 对于只需要执行一次的副作用,使用空依赖数组
- 对于依赖于特定值的副作用,将这些值添加到依赖数组中
- 避免使用空依赖数组时引用可能变化的值
3. 自定义 Hook 命名
- 自定义 Hook 应该以
use开头 - 使用描述性的名称,反映 Hook 的功能
4. 状态管理
- 对于简单的状态,使用 useState
- 对于复杂的状态,考虑使用 useReducer
- 对于跨组件共享的状态,使用 Context API
5. 性能优化
- 使用 useCallback 缓存函数
- 使用 useMemo 缓存计算结果
- 使用 useRef 存储不需要触发重新渲染的值
7. 总结
Hooks 是 React 和 React Native 中管理状态和副作用的强大工具:
- useState:用于管理组件的状态
- useEffect:用于执行副作用操作
- 自定义 Hook:用于复用状态逻辑
掌握 Hooks,你可以创建出更加简洁、可维护的 React Native 应用。
在使用 Hooks 时,要注意:
- 只在函数组件的顶部使用 Hook
- 合理使用依赖数组
- 遵循 Hook 的命名约定
- 注意性能优化
至此,我们已经完成了 React 基础的学习。在接下来的教程中,我们将开始学习 React Native 的核心基础,包括核心组件、样式和布局等。
