1. 项目组件设计
组件书写思维
-
需要职责分层
// Service层:纯业务逻辑 const userService = { async getUsers() { /* API调用 */ }, async deleteUser(id) { /* 删除逻辑 */ } }; // Hook层:状态管理和副作用 const useUserList = () => { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); const deleteUser = async (id) => { setLoading(true); await userService.deleteUser(id); setUsers(prev => prev.filter(u => u.id !== id)); setLoading(false); }; return { users, loading, deleteUser }; }; // UI层:纯渲染逻辑 function UserList() { const { users, loading, deleteUser } = useUserList(); if (loading) return<LoadingSpinner />; return ( <div> {users.map(user => ( <UserCard key={user.id} user={user} onDelete={() => deleteUser(user.id)} /> ))} </div> ); }
公共组件提取规则
- 第一次写:直接写
- 第二次遇到:复制粘贴
- 第三次遇到:开始抽象
React 组件设计
1. UI + Container 模式
将组件拆分为两类:
- Container 组件:处理数据获取、state 和逻辑。
- UI 组件:只负责展示
// Container 组件
function UserContainer() {
const { data, isLoading } = useQuery('user', fetchUser);
return <UserProfile user={data} loading={isLoading} />;
}
// UI 组件
function User({ userInfo, loading }) {
if (loading) return <Skeleton />;
return <div>{userInfo.name}</div>;
}
2. Controlled + Uncontrolled 模式
- Controlled 组件:父组件通过 props 管理 value。
- Uncontrolled 组件:内部通过 ref 自行管理 state。
// Controlled 组件
<input value={value} onChange={e => setValue(e.target.value)} />
// Uncontrolled 组件
<input defaultValue="Hello" ref={inputRef} />
3. State + Context 模式
- 通过共享 state 和 context 设计父子组件关系。
- 父组件管理逻辑,并通过 context 而不是 props 向子组件传递控制权。
<Tabs>
<Tabs.List>
<Tabs.Trigger value="posts">Posts</Tabs.Trigger>
<Tabs.Trigger value="comments">Comments</Tabs.Trigger>
</Tabs.List>
<Tabs.Panel value="posts">Post content</Tabs.Panel>
<Tabs.Panel value="comments">Comment content</Tabs.Panel>
</Tabs>
4. State + Reducer 模式
- 允许用户覆盖内部的 state 转换逻辑。
- 组件内部使用 reducer,同时允许消费者注入自定义逻辑。
function useToggle({ reducer = defaultReducer } = {}) {
const [state, dispatch] = useReducer(reducer, { on: false });
const toggle = () => dispatch({ type: 'toggle' });
return [state.on, toggle];
}
5. Props 配置 + Children 组合
- 使用 props 配置行为。
- 使用 children 组合 UI。
<Card variant="elevated">
<Card.Title>Settings</Card.Title>
<Card.Body>
<SettingsForm />
</Card.Body>
</Card>
2. 项目架构设计
为变化而设计
const createApiClient = (baseURL, defaultHeaders) => ({
get: (endpoint) => fetch(`${baseURL}${endpoint}`, {
headers: defaultHeaders
}),
post: (endpoint, data) => fetch(`${baseURL}${endpoint}`, {
method: 'POST',
headers: { ...defaultHeaders, 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
});
const apiClient = createApiClient(
process.env.API_BASE_URL,
{ Authorization: `Bearer ${getToken()}` }
);
状态管理局部化
- 局部状态优先,全局状态谨慎
// 组件级状态:用useState/useReducer
function ProductCard() {
const [isExpanded, setIsExpanded] = useState(false);
return (<div>
{ isExpanded ? <ProductDetail /> : null }
</div>)
}
import { observable, action, computed, makeObservable } from 'mobx';
// 购物车功能级状态 - 使用 makeObservable
const createShoppingCartStore = () => {
const store = {
items: [],
addItem(item) {
store.items.push(item);
},
removeItem(id) {
store.items = store.items.filter(item => item.id !== id);
},
clearCart() {
store.items = [];
},
get totalItems() {
return store.items.length;
},
get totalPrice() {
return store.items.reduce((total, item) => total + (item.price || 0), 0);
}
};
makeObservable(store, {
items: observable,
addItem: action,
removeItem: action,
clearCart: action,
totalItems: computed,
totalPrice: computed
});
return store;
};
// 认证应用级状态 - 使用 makeObservable
const createAuthStore = () => {
const store = {
user: null,
token: null,
isLoading: false,
error: null,
async login(credentials) {
this.isLoading = true;
this.error = null;
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(credentials),
});
if (!response.ok) {
throw new Error('登录失败');
}
const data = await response.json();
runInAction(() => {
this.user = data.user;
this.token = data.token;
this.isLoading = false;
});
} catch (error) {
runInAction(() => {
this.error = error.message;
this.isLoading = false;
});
throw error;
}
},
logout() {
this.user = null;
this.token = null;
this.error = null;
},
get isAuthenticated() {
return !!this.user && !!this.token;
}
};
makeObservable(store, {
user: observable,
token: observable,
isLoading: observable,
error: observable,
login: action,
logout: action,
isAuthenticated: computed
});
return store;
};
路由设计
- 性能优先的路由设计
const Dashboard = lazy(() =>import('./pages/Dashboard'));
const Analytics = lazy(() =>import('./pages/Analytics'));
const Settings = lazy(() =>import('./pages/Settings'));
function App() {
return (
<Router>
<Suspense fallback={<PageSkeleton />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/analytics" element={<Analytics />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</Router>
);
}
// 基于路由的预加载策略
const useRoutePreloading = () => {
useEffect(() => {
// 预加载用户可能访问的路由
const currentPath = location.pathname;
if (currentPath === '/dashboard') {
import('./pages/Analytics'); // 预加载分析页面
}
}, []);
};
微前端模块联邦
- 整合不同技术栈:每个项目可以用不同的技术栈
- 运行时组合:模块可以动态加载和卸载
- 共享依赖优化:避免重复加载相同的库
- 版本独立部署:一个模块的更新不影响其他模块
Webpack项目
// 宿主应用配置
const ModuleFederationPlugin = require('@module-federation/webpack');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
userModule: 'user@http://localhost:3001/remoteEntry.js',
productModule: 'product@http://localhost:3002/remoteEntry.js',
orderModule: 'order@http://localhost:3003/remoteEntry.js'
},
shared: {
react: { singleton: true },
}
})
]
};
// 动态加载远程模块
const UserManagement = lazy(() =>import('userModule/UserManagement'));
const ProductCatalog = lazy(() =>import('productModule/ProductCatalog'));
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/users/*" element={
<Suspense fallback={<PageSkeleton />}>
<UserManagement />
</Suspense>
} />
<Route path="/products/*" element={
<Suspense fallback={<PageSkeleton />}>
<ProductCatalog />
</Suspense>
} />
</Routes>
</BrowserRouter>
);
}
Umi项目
// .umirc.ts
import { defineConfig } from 'umi';
const shared = {
react: {
singleton: true,
eager: true,
},
'react-dom': {
singleton: true,
eager: true,
},
};
export default defineConfig({
plugins: ['@umijs/plugins/dist/mf'], // 引入插件
mf: {
remotes: [
{
// 可选,未配置则使用当前 remotes[].name 字段
aliasName: 'mfNameAlias',
name: 'theMfName',
entry: 'https://to.the.remote.com/remote.js',
},
],
// 配置 MF 共享的模块
shared,
},
});
注:详细教程 umijs.org/docs/max/mf