react-redux 的核心是 订阅 store 变化 并 触发组件重新渲染。它利用 React 的 context 和 useSyncExternalStore 来高效地管理状态和 UI 更新。下面详细讲解 react-redux 是如何更新界面的。
react-redux 更新 UI 的流程
- **组件连接 Redux store**(Provider 共享全局状态)
- 组件订阅 store 变化(useSelector / connect 监听数据变化)
- **状态改变时,触发 store.subscribe**(Redux dispatch 触发 store 更新)
- 对比新旧状态,决定是否重新渲染(避免不必要的 UI 更新)
- 通知组件重新渲染(React useState 或 forceUpdate 触发渲染)
1. Redux store 如何连接到 React
在 react-redux 中,我们通过 Provider 让整个应用访问 store:
import { Provider } from "react-redux";
import { store } from "./store";
export default function App() {
return (
<Provider store={store}>
<MyComponent />
</Provider>
);
}
- Provider 使用 React Context 传递 store。
- 子组件可以用 useSelector 访问 Redux 状态。
2. 组件如何订阅 Redux 状态
组件可以使用 useSelector 订阅 store 里的状态:
import { useSelector } from "react-redux";
function MyComponent() {
const count = useSelector(state => state.counter.value);
return <p>Count: {count}</p>;
}
useSelector 如何监听状态变化?
- useSelector 内部会调用 store.subscribe() 订阅 Redux store 变化
- 当 dispatch 修改 store 时,所有 useSelector 订阅的组件都会执行
- useSelector 会对比新旧状态(默认用 === 浅比较)
- 如果状态没变,组件不会重新渲染,避免不必要的更新
3. Redux dispatch 如何触发 UI 更新
组件通过 dispatch 触发 Redux store 更新:
import { useDispatch } from "react-redux";
import { increment } from "./counterSlice";
function MyComponent() {
const dispatch = useDispatch();
return <button onClick={() => dispatch(increment())}>+1</button>;
}
dispatch 更新流程
- dispatch(action) 触发 Redux store 更新
- Redux reducer 计算新 state
- store 触发 store.subscribe() 通知所有 useSelector 订阅的组件
- useSelector 比较状态,如果变化则触发组件 重新渲染
4. react-redux 内部是如何订阅 store 的?
useSelector 的底层实现
在 react-redux 中,useSelector 用 useSyncExternalStore 监听 store:
import { useSyncExternalStore } from "react";
function useSelector(selector) {
const store = useContext(StoreContext);
return useSyncExternalStore(
store.subscribe, // 订阅 Redux store
() => selector(store.getState()) // 获取最新状态
);
}
useSyncExternalStore 如何工作?
- **订阅
store
**(store.subscribe
) - 检测状态是否变化(通过
store.getState()
获取最新值) - 如果状态变了,触发组件重新渲染(React 重新执行组件)
Redux 更新 UI 的完整流程
- dispatch(action) 触发 store 更新
- reducer 计算新 state
- store 调用 store.subscribe() 通知组件
- 组件的 useSelector 重新执行,并对比状态
- 如果状态变化,则 触发 React 重新渲染
react-redux UI 更新的优化
1. 避免不必要的渲染
- useSelector 只会让组件更新受影响的状态,而不是整个 store。
- 默认使用 === 浅比较,确保状态真的变化才会触发渲染:
const value = useSelector(state => state.value, (a, b) => a === b);
- 如果 useSelector 依赖对象,可以使用 reselect 进行 Memoization。
2. 使用 useCallback 和 useMemo
- useDispatch() 生成的 dispatch 函数不会变,但 useSelector 可能导致组件重新渲染:
const data = useMemo(() => expensiveCalculation(state), [state]);
const handleClick = useCallback(() => dispatch(increment()), [dispatch]);
3. 代码分片(Lazy Load)
- 使用 redux-toolkit 的 lazyReducerEnhancer 进行动态加载 reducer,减少初始化开销。
总结
步骤 | React Redux UI 更新流程 |
1. 组件连接 store | Provider 通过 Context 提供 Redux store |
2. 组件订阅状态 | useSelector 监听 store 变化 |
3. 状态变更 | dispatch 触发 store 更新 |
4. 组件重新渲染 | useSyncExternalStore 检测状态变更,触发 UI 更新 |
5. 性能优化 | useSelector 只更新受影响的组件,减少不必要渲染 |
React-Redux 通过 useSelector 监听 store,dispatch 触发 store 变更,useSyncExternalStore 检测 state 变化,决定是否重新渲染组件,从而实现高效的 UI 更新。