一、React 状态驱动(触发组件重新 render)
这类更新的本质:状态变化 → React 调度更新 → 重新执行组件函数 → 虚拟 DOM diff → 提交到原生 View。
1. useState – 最基本的状态
import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={() => setCount(count + 1)} />
</View>
);
}
原理:
调用 setCount 时,React 内部会将当前 Fiber 节点标记为“需要更新”,并产生一个更新对象进入队列。在下一次渲染周期(通常由事件处理函数结束后批量执行),React 重新执行 Counter 函数,通过 Hook 链表拿到最新的 count 值,生成新的虚拟 DOM,对比差异后更新原生 Text 和 View。
2. useReducer – 复杂状态逻辑
import React, { useReducer } from 'react';
import { View, Text, Button } from 'react-native';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
}
export default function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<View>
<Text>Count: {state.count}</Text>
<Button title="+" onPress={() => dispatch({ type: 'increment' })} />
<Button title="-" onPress={() => dispatch({ type: 'decrement' })} />
</View>
);
}
原理:
dispatch 一个 action 后,reducer 根据当前状态和 action 计算出新状态。React 使用该新状态触发一次组件 re-render,过程与 useState 完全一致。useReducer 适合状态更新逻辑较复杂或需要依赖旧状态的场景。
3. useContext – 跨组件共享数据
import React, { useContext, useState } from 'react';
import { View, Text, Button } from 'react-native';
const ThemeContext = React.createContext('light');
function ThemedText() {
const theme = useContext(ThemeContext);
return <Text style={{ color: theme === 'dark' ? 'white' : 'black' }}>Hello</Text>;
}
export default function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<View>
<ThemedText />
<Button title="Toggle Dark" onPress={() => setTheme(theme === 'light' ? 'dark' : 'light')} />
</View>
</ThemeContext.Provider>
);
}
原理:
ThemeContext.Provider 的 value 变化时,React 会遍历消费者 fiber 树,找到所有使用了该 Context 的组件(如 ThemedText),强制它们重新渲染,即使它们的 props 没有变化。这种更新不依赖中间组件的 shouldComponentUpdate。
4. 父组件 props 变化(默认子组件会更新)
import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
const Child = ({ value }) => {
console.log('Child render');
return <Text>{value}</Text>;
};
export default function Parent() {
const [count, setCount] = useState(0);
return (
<View>
<Child value={count} />
<Button title="Increment" onPress={() => setCount(count + 1)} />
</View>
);
}
原理:
父组件 setCount 触发自身重渲染,在生成新的 React 元素时,Child 的 props 对象被重新创建({ value: count } 是一个新对象)。即使 value 值相同,默认情况下子组件也会重渲染。若想跳过,需使用 React.memo。
5. 类组件 setState / forceUpdate
import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
export default class Counter extends Component {
state = { count: 0 };
render() {
return (
<View>
<Text>{this.state.count}</Text>
<Button title="Increment" onPress={() => this.setState({ count: this.state.count + 1 })} />
</View>
);
}
}
原理:
setState 将新状态合并到 this.state,并触发组件更新流程:shouldComponentUpdate → render → 生成虚拟 DOM → diff → 更新原生 View。forceUpdate 会跳过 shouldComponentUpdate 直接强制更新。
二、状态管理库(本质仍触发 React re‑render)
这些库在 React 外部维护状态,但通过订阅机制最终调用 React 的更新函数(如 setState 或 useState 的 setter)。
6. MobX + observer
import React from 'react';
import { View, Text, Button } from 'react-native';
import { observable } from 'mobx';
import { observer } from 'mobx-react-lite';
// 可观察的 store
const store = observable({
count: 0,
increment() {
this.count++;
}
});
// observer 包装组件
const Counter = observer(() => {
return (
<View>
<Text>Count: {store.count}</Text>
<Button title="+" onPress={() => store.increment()} />
</View>
);
});
export default Counter;
原理:
observer 在组件首次渲染时,通过代理访问 store.count,MobX 会记录该组件依赖了 count。当 store.increment 修改 count 时,MobX 知道这个组件需要更新,便调用组件内部的一个强制更新函数(类似 forceUpdate),触发 React 重新执行组件函数,从而得到新值。注意:这仍然是 React re‑render,只是依赖收集由 MobX 自动完成。
7. Redux Toolkit + useSelector / useDispatch
import React from 'react';
import { View, Text, Button } from 'react-native';
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useDispatch, useSelector } from 'react-redux';
// 创建 slice
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
incremented: state => { state.value += 1; }
}
});
const store = configureStore({ reducer: counterSlice.reducer });
// 组件
const Counter = () => {
const count = useSelector(state => state.value);
const dispatch = useDispatch();
return (
<View>
<Text>{count}</Text>
<Button title="+" onPress={() => dispatch(counterSlice.actions.incremented())} />
</View>
);
};
// App 根组件需用 Provider 包裹
export default function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
原理:
dispatch action 后,Redux 执行 reducer 更新 store,然后通知所有订阅者。useSelector 内部会订阅 Redux store,store 变化时调用 useSyncExternalStore(或旧版的 useReducer 强制更新)来触发组件 re‑render。同时 useSelector 会对返回的值做浅比较,只有变化时才触发更新,避免无意义渲染。
8. Zustand – 轻量状态
import React from 'react';
import { View, Text, Button } from 'react-native';
import { create } from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));
export default function Counter() {
const { count, increment } = useCounterStore();
return (
<View>
<Text>{count}</Text>
<Button title="+" onPress={increment} />
</View>
);
}
原理:
Zustand 在 store 内部维护状态和监听器列表。useCounterStore hook 会订阅 store,并在组件首次渲染时注册一个强制更新函数(基于 useSyncExternalStore 或 useReducer)。当 increment 调用 set 更新状态后,Zustand 遍历所有订阅者,执行它们的强制更新函数,从而触发对应组件重渲染。
三、动画 / 命令式更新(不触发 React re‑render)
这类更新不走 React 的 diff 和生命周期,直接在原生层或通过特殊的动画系统修改视图属性。
9. Animated + useNativeDriver: true
import React, { useRef, useEffect } from 'react';
import { Animated, View, Text } from 'react-native';
export default function FadeInView() {
const fadeAnim = useRef(new Animated.Value(0)).current; // 初始透明度 0
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 2000,
useNativeDriver: true, // 关键:启用原生驱动
}).start();
}, []);
return (
<Animated.View style={{ opacity: fadeAnim }}>
<Text>我会渐渐显示出来</Text>
</Animated.View>
);
}
原理:
Animated.Value 是一个可驱动变量。当启动 timing 动画时,React Native 会创建一个原生动画对象,并在 UI 线程中逐帧计算插值,直接修改原生 View 的 opacity 属性。每一帧都不经过 JavaScript 线程(除了初始化和结束回调),因此不会触发 React 组件的 render 方法。动画结束后如果没有任何 setState,组件不会重渲染。
10. react-native-reanimated v2(UI 线程动画)
import React from 'react';
import { View, Button } from 'react-native';
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
export default function AnimatedBox() {
const width = useSharedValue(100); // 共享值,原生侧存储
const animatedStyle = useAnimatedStyle(() => {
return {
width: width.value,
height: width.value,
backgroundColor: 'blue',
};
});
const handlePress = () => {
width.value = withTiming(width.value === 100 ? 200 : 100, { duration: 500 });
};
return (
<View>
<Animated.View style={animatedStyle} />
<Button title="Change Size" onPress={handlePress} />
</View>
);
}
原理:
useSharedValue 在原生侧分配一块共享内存,JS 和 UI 线程都能访问其值。useAnimatedStyle 在 UI 线程中创建一个响应式闭包:当 width.value 变化时(比如由 withTiming 动画驱动),UI 线程会重新执行该闭包,计算出新样式,然后直接更新原生 View 的布局属性。整个过程不经过 React 的渲染周期,性能极高。
11. ref + setNativeProps(命令式原生更新)
import React, { useRef } from 'react';
import { View, Text, Button, findNodeHandle, UIManager } from 'react-native';
export default function NativePropsDemo() {
const viewRef = useRef(null);
const changeBackground = () => {
// 直接修改原生 View 的背景色,不触发 React 重渲染
UIManager.updateView(
findNodeHandle(viewRef.current),
viewRef.current?.getNativeHandle?.() || 'RCTView',
{ backgroundColor: 0x00ff00ff } // 绿色 ARGB
);
};
// 或者使用更简单的 setNativeProps(仅部分组件支持)
const changeText = () => {
viewRef.current?.setNativeProps?.({ style: { backgroundColor: 'red' } });
};
return (
<View>
<View ref={viewRef} style={{ width: 100, height: 100, backgroundColor: 'blue' }} />
<Button title="Change via setNativeProps" onPress={changeText} />
</View>
);
}
原理:
setNativeProps 或 UIManager.updateView 直接调用原生模块的方法,跳过 React 的属性 diff 和更新队列。这种方式不会触发组件的 render,也不会让 React 知道属性的变化。通常不推荐用于常规 UI,但在需要极致性能(如高频输入框样式更新)或与原生 SDK 深度集成时有用。
总结对照表
| 方式 | 是否触发 React re‑render | 原理摘要 |
|---|---|---|
useState / useReducer
|
✅ | 状态变化 → 调度更新 → 重新执行函数组件 → diff → 原生更新。 |
useContext |
✅ | Provider value 变化 → 强制消费组件重渲染,无视中间组件优化。 |
| 父组件 props 变化 | ✅(默认) | 父重渲染时子默认重渲染,除非 memo / PureComponent 拦截。 |
MobX + observer
|
✅ | 自动收集依赖,数据变化时调用组件的强制更新函数。 |
| Redux / Zustand / Recoil | ✅ | store 变化 → 通知订阅者 → 调用 hook 内部的强制更新函数 → 组件重渲染。 |
Animated (native driver) |
❌ | 原生动画驱动,每帧直接在 UI 线程修改 transform/opacity,不经过 JS 线程。 |
| Reanimated v2 | ❌ | UI 线程执行响应式样式更新,shared value 变化直接更新原生 View。 |
setNativeProps / ref |
❌ | 直接调用原生模块的更新方法,完全绕过 React。 |
现在您已经有了完整可运行的代码示例以及清晰的原理说明,可以实际动手测试每种方式的行为差异。