React 深度開(kāi)發(fā)
// src/actions/types.js
export const USER_LOGIN = 'USER_LOGIN';
export const USER_LOGOUT = 'USER_LOGOUT';
export const SET_TOKEN = 'SET_TOKEN';
export const SET_MENUS = 'SET_MENUS';
export const SET_LOADING = 'SET_LOADING';
export const SET_ERROR = 'SET_ERROR';
export const CLEAR_ERROR = 'CLEAR_ERROR';
// src/actions/userActions.js
import * as types from './types';
// 用戶(hù)登錄
export const userLogin = (userInfo) => ({
type: types.USER_LOGIN,
payload: userInfo
});
// 用戶(hù)登出
export const userLogout = () => ({
type: types.USER_LOGOUT
});
// 設置token
export const setToken = (token) => ({
type: types.SET_TOKEN,
payload: token
});
// 設置菜單
export const setMenus = (menus) => ({
type: types.SET_MENUS,
payload: menus
});
// 異步登錄Action
export const loginUser = (username, password) => {
return async (dispatch) => {
dispatch(setLoading(true));
try {
const res = await post(allUrl.user.login, {}, {
userId: username,
password: md5(password)
});
if (res.msgKey) {
dispatch(userLogin(res.result));
dispatch(setToken(res.result.token));
sessionStorage.setItem('token', res.result.token);
} else {
dispatch(setError(res.msgInfo));
}
} catch (error) {
dispatch(setError('登錄失敗'));
} finally {
dispatch(setLoading(false));
}
};
};
// src/reducers/userReducer.js
import * as types from '../actions/types';
const initialState = {
token: sessionStorage.getItem('token') || '',
userInfo: {},
menus: [],
account: {}
};
const userReducer = (state = initialState, action) => {
switch (action.type) {
case types.USER_LOGIN:
return {
...state,
userInfo: action.payload,
account: action.payload.account || {}
};
case types.USER_LOGOUT:
sessionStorage.removeItem('token');
return {
...initialState,
token: ''
};
case types.SET_TOKEN:
return {
...state,
token: action.payload
};
case types.SET_MENUS:
return {
...state,
menus: action.payload
};
default:
return state;
}
};
export default userReducer;
// src/reducers/commonReducer.js
import * as types from '../actions/types';
const initialState = {
loading: false,
error: null,
success: null
};
const commonReducer = (state = initialState, action) => {
switch (action.type) {
case types.SET_LOADING:
return {
...state,
loading: action.payload
};
case types.SET_ERROR:
return {
...state,
error: action.payload,
success: null
};
case types.CLEAR_ERROR:
return {
...state,
error: null
};
case types.SET_SUCCESS:
return {
...state,
success: action.payload,
error: null
};
default:
return state;
}
};
export default commonReducer;
// src/components/UserProfile.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { userLogout, setMenus } from '../actions/userActions';
class UserProfile extends Component {
componentDidMount() {
// 組件掛載時(shí)加載菜單
this.loadMenus();
}
loadMenus = async () => {
const { setMenus } = this.props;
try {
const res = await post(allUrl.user.getMenus, {});
if (res.msgKey) {
setMenus(res.result);
}
} catch (error) {
console.error('加載菜單失敗:', error);
}
};
handleLogout = () => {
this.props.userLogout();
this.props.history.push('/login');
};
render() {
const { userInfo, menus, loading } = this.props;
return (
<div className="user-profile">
<div>歡迎, {userInfo.userName}</div>
<Button onClick={this.handleLogout}>退出登錄</Button>
{loading && <Spin />}
<Menu mode="horizontal" selectedKeys={[]}>
{menus.map(menu => (
<Menu.Item key={menu.zyDm}>
{menu.zyMc}
</Menu.Item>
))}
</Menu>
</div>
);
}
}
// 映射state到props
const mapStateToProps = (state) => ({
userInfo: state.user.userInfo,
menus: state.user.menus,
loading: state.common.loading
});
// 映射dispatch到props
const mapDispatchToProps = {
userLogout,
setMenus
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
// 使用Hooks的函數組件
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { setLoading, clearError } from '../actions/commonActions';
const UserDashboard = () => {
const userInfo = useSelector(state => state.user.userInfo);
const loading = useSelector(state => state.common.loading);
const error = useSelector(state => state.common.error);
const dispatch = useDispatch();
const handleRefresh = async () => {
dispatch(setLoading(true));
try {
// 刷新數據邏輯
await refreshUserData();
} catch (error) {
console.error('刷新失敗:', error);
} finally {
dispatch(setLoading(false));
}
};
if (error) {
return (
<Alert
message="錯誤"
description={error}
type="error"
closable
onClose={() => dispatch(clearError())}
/>
);
}
return (
<div className="user-dashboard">
<Card title="用戶(hù)信息">
<p>用戶(hù)名: {userInfo.userName}</p>
<p>公司: {userInfo.companyName}</p>
<Button onClick={handleRefresh} loading={loading}>
刷新數據
</Button>
</Card>
</div>
);
};
export default UserDashboard;
// 配置promise中間件
import promiseMiddleware from 'redux-promise-middleware';
const store = createStore(
rootReducer,
applyMiddleware(promiseMiddleware)
);
// 使用promise中間件的Action
export const fetchUserData = () => ({
type: 'FETCH_USER_DATA',
payload: post(allUrl.user.getInfo, {})
});
// Reducer處理promise中間件生成的action
const userReducer = (state = initialState, action) => {
switch (action.type) {
case 'FETCH_USER_DATA_PENDING':
return { ...state, loading: true };
case 'FETCH_USER_DATA_FULFILLED':
return {
...state,
loading: false,
userInfo: action.payload.result
};
case 'FETCH_USER_DATA_REJECTED':
return {
...state,
loading: false,
error: action.payload
};
default:
return state;
}
};
// 日志中間件
const loggerMiddleware = store => next => action => {
console.log('dispatching:', action);
const result = next(action);
console.log('next state:', store.getState());
return result;
};
// 錯誤處理中間件
const errorHandlerMiddleware = store => next => action => {
try {
return next(action);
} catch (error) {
console.error('Action執行錯誤:', error);
store.dispatch(setError(error.message));
throw error;
}
};
// 應用中間件
const store = createStore(
rootReducer,
applyMiddleware(loggerMiddleware, errorHandlerMiddleware, promiseMiddleware)
);
// 持久化配置
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
storage,
whitelist: ['user'], // 只持久化用戶(hù)相關(guān)狀態(tài)
blacklist: ['common'] // 不持久化通用狀態(tài)
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
// 創(chuàng )建持久化store
const store = createStore(persistedReducer);
const persistor = persistStore(store);
// 自定義序列化轉換器
import { createTransform } from 'redux-persist';
// 只持久化部分用戶(hù)信息
const userTransform = createTransform(
// 存入時(shí)的轉換
(inboundState, key) => {
return {
token: inboundState.token,
userInfo: {
userId: inboundState.userInfo.userId,
userName: inboundState.userInfo.userName
}
};
},
// 取出時(shí)的轉換
(outboundState, key) => {
return outboundState;
},
{ whitelist: ['user'] }
);
const persistConfig = {
key: 'root',
storage,
transforms: [userTransform]
};
// 創(chuàng )建記憶化選擇器
import { createSelector } from 'reselect';
// 基礎選擇器
const getUser = state => state.user;
const getMenus = state => state.user.menus;
// 記憶化選擇器
export const getActiveMenus = createSelector(
[getMenus],
(menus) => menus.filter(menu => menu.status === 'active')
);
export const getUserPermissions = createSelector(
[getUser],
(user) => user.userInfo.permissions || []
);
// 在組件中使用
const mapStateToProps = (state) => ({
activeMenus: getActiveMenus(state),
permissions: getUserPermissions(state)
});
// 使用React.memo優(yōu)化函數組件
const UserList = React.memo(({ users, onUserSelect }) => {
return (
<List
dataSource={users}
renderItem={user => (
<List.Item onClick={() => onUserSelect(user)}>
{user.userName}
</List.Item>
)}
/>
);
});
// 使用shouldComponentUpdate優(yōu)化類(lèi)組件
class UserTable extends Component {
shouldComponentUpdate(nextProps, nextState) {
// 只有當users數據變化時(shí)才重新渲染
return nextProps.users !== this.props.users;
}
render() {
// 渲染邏輯
}
}
// 錯誤邊界組件
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 將錯誤發(fā)送到Redux store
this.props.dispatch(setError(error.message));
console.error('組件錯誤:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <ErrorFallback />;
}
return this.props.children;
}
}
export default connect()(ErrorBoundary);
// 統一的錯誤處理函數
const handleAsyncError = (error, dispatch) => {
if (error.response) {
// 服務(wù)器返回錯誤
dispatch(setError(error.response.data.message));
} else if (error.request) {
// 網(wǎng)絡(luò )錯誤
dispatch(setError('網(wǎng)絡(luò )連接失敗'));
} else {
// 其他錯誤
dispatch(setError(error.message));
}
};
// 在A(yíng)ction中使用
export const fetchData = () => async (dispatch) => {
try {
const data = await api.fetchData();
dispatch({ type: 'FETCH_SUCCESS', payload: data });
} catch (error) {
handleAsyncError(error, dispatch);
}
};
這些Redux使用模式為應用提供了強大的狀態(tài)管理能力,包括數據流控制、異步操作處理、性能優(yōu)化和錯誤處理。