设计思路
- 错误捕获:在React组件中,使用
try - catch
块或者componentDidCatch
(类组件)、useErrorBoundary
(函数组件使用React 18+)来捕获错误。
- 错误传递到Redux:将捕获到的错误通过Redux的action传递给store。
- 集中处理:在reducer中处理这些错误action,更新store中的错误状态。
- 避免不必要渲染:利用Redux的
shouldComponentUpdate
(类组件)或者React.memo
(函数组件),结合reselect
库来计算派生数据,只有当真正相关的数据变化时才进行渲染。
涉及技术点
- Redux:用于状态管理,包括actions、reducers和store。
- React Error Boundaries:用于捕获子组件树中的JavaScript错误。
- Reselect:用于创建高效的selector,避免不必要的计算和渲染。
代码示例
- React组件(函数组件)
import React, { useCallback } from'react';
import { useDispatch } from'react-redux';
const MyComponent = () => {
const dispatch = useDispatch();
const handleApiCall = useCallback(() => {
try {
// 模拟API调用,这里会抛出错误
throw new Error('API call failed');
} catch (error) {
dispatch({ type: 'API_CALL_ERROR', payload: error.message });
}
}, [dispatch]);
return (
<div>
<button onClick={handleApiCall}>触发API调用</button>
</div>
);
};
export default MyComponent;
- Redux相关代码
export const apiCallError = (errorMessage) => ({
type: 'API_CALL_ERROR',
payload: errorMessage
});
- **reducers.js**
const initialState = {
error: null
};
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'API_CALL_ERROR':
return {
...state,
error: action.payload
};
default:
return state;
}
};
export default rootReducer;
- **store.js**
import { createStore } from'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
export default store;
- **App.js(使用Redux Provider)**
import React from'react';
import ReactDOM from'react-dom';
import { Provider } from'react-redux';
import store from './store';
import MyComponent from './MyComponent';
const App = () => (
<Provider store={store}>
<MyComponent />
</Provider>
);
ReactDOM.render(<App />, document.getElementById('root'));
- 使用Reselect(可选,用于优化)
import { createSelector } from'reselect';
const selectError = state => state.error;
const selectErrorMessage = createSelector(
[selectError],
error => error? `错误: ${error}` : null
);
export { selectErrorMessage };
- **更新后的MyComponent.js**
import React from'react';
import { useDispatch, useSelector } from'react-redux';
import { selectErrorMessage } from './selectors';
const MyComponent = () => {
const dispatch = useDispatch();
const errorMessage = useSelector(selectErrorMessage);
const handleApiCall = () => {
try {
throw new Error('API call failed');
} catch (error) {
dispatch({ type: 'API_CALL_ERROR', payload: error.message });
}
};
return (
<div>
<button onClick={handleApiCall}>触发API调用</button>
{errorMessage && <p>{errorMessage}</p>}
</div>
);
};
export default MyComponent;