关于 react-modernization
这项技能介绍如何通过版本升级、类组件迁移到 Hooks 以及采用 React 18 功能来现代化 React 应用,面向维护或重构 React 项目的开发者。
主要功能
- 01React 版本升级指导
- 02类组件迁移到 Hooks
- 03React 18 并发功能
- 04借助 Codemod 重构
- 05状态管理模式现代化
适用场景
- 01升级现有 React 应用
- 02将类组件替换为 Hooks
- 03采用 Suspense 和 transitions
- 04更新项目模式以使用 TypeScript
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ wshobson/ agents --skill react-modernization安装后在 Claude Code 中输入/react-modernization确认已加载。
附带文件references/details.md
详细介绍
React 现代化
掌握 React 版本升级、类组件到 Hook 的迁移、并发特性的采用,以及用于自动化转换的 codemod。
何时使用此技能
- 将 React 应用升级到最新版本
- 将类组件迁移到带 Hook 的函数组件
- 采用 React 并发特性(Suspense、过渡)
- 应用 codemod 进行自动化重构
- 现代化状态管理模式
- 升级到 TypeScript
- 利用 React 18+ 特性提升性能
版本升级路径
React 16 → 17 → 18
各版本的破坏性变更:
React 17:
- 事件委托变更
- 移除事件池化
- 副作用清理时机
- JSX 转换(无需导入 React)
React 18:
- 自动批处理
- 并发渲染
- Strict Mode 变更(双重调用)
- 新的 root API
- 服务端 Suspense
类组件到 Hook 的迁移
状态管理
// Before: Class component
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
name: "",
};
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
// After: Functional component with hooks
function Counter() {
const [count, setCount] = useState(0);
const [name, setName] = useState("");
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
生命周期方法到 Hook
// Before: Lifecycle methods
class DataFetcher extends React.Component {
state = { data: null, loading: true };
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.fetchData();
}
}
componentWillUnmount() {
this.cancelRequest();
}
fetchData = async () => {
const data = await fetch(`/api/${this.props.id}`);
this.setState({ data, loading: false });
};
cancelRequest = () => {
// Cleanup
};
render() {
if (this.state.loading) return <div>Loading...</div>;
return <div>{this.state.data}</div>;
}
}
// After: useEffect hook
function DataFetcher({ id }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
const fetchData = async () => {
try {
const response = await fetch(`/api/${id}`);
const result = await response.json();
if (!cancelled) {
setData(result);
setLoading(false);
}
} catch (error) {
if (!cancelled) {
console.error(error);
}
}
};
fetchData();
// Cleanup function
return () => {
cancelled = true;
};
}, [id]); // Re-run when id changes
if (loading) return <div>Loading...</div>;
return <div>{data}</div>;
}
Context 和 HOC 到 Hook
// Before: Context consumer and HOC
const ThemeContext = React.createContext();
class ThemedButton extends React.Component {
static contextType = ThemeContext;
render() {
return (
<button style={{ background: this.context.theme }}>
{this.props.children}
</button>
);
}
}
// After: useContext hook
function ThemedButton({ children }) {
const { theme } = useContext(ThemeContext);
return <button style={{ background: theme }}>{children}</button>;
}
// Before: HOC for data fetching
function withUser(Component) {
return class extends React.Component {
state = { user: null };
componentDidMount() {
fetchUser().then((user) => this.setState({ user }));
}
render() {
return <Component {...this.props} user={this.state.user} />;
}
};
}
// After: Custom hook
function useUser() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(setUser);
}, []);
return user;
}
function UserProfile() {
const user = useUser();
if (!user) return <div>Loading...</div>;
return <div>{user.name}</div>;
}
React 18 并发特性
新的 root API
// Before: React 17
import ReactDOM from "react-dom";
ReactDOM.render(<App />, document.getElementById("root"));
// After: React 18
import { createRoot } from "react-dom/client";
const root = createRoot(document.getElementById("root"));
root.render(<App />);
自动批处理
// React 18: All updates are batched
function handleClick() {
setCount((c) => c + 1);
setFlag((f) => !f);
// Only one re-render (batched)
}
// Even in async:
setTimeout(() => {
setCount((c) => c + 1);
setFlag((f) => !f);
// Still batched in React 18!
}, 1000);
// Opt out if needed
import { flushSync } from "react-dom";
flushSync(() => {
setCount((c) => c + 1);
});
// Re-render happens here
setFlag((f) => !f);
// Another re-render
过渡
import { useState, useTransition } from "react";
function SearchResults() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
// Urgent: Update input immediately
setQuery(e.target.value);
// Non-urgent: Update results (can be interrupted)
startTransition(() => {
setResults(searchResults(e.target.value));
});
};
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<Results data={results} />
</>
);
}
用于数据获取的 Suspense
import { Suspense } from "react";
// Resource-based data fetching (with React 18)
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<Loading />}>
<ProfileDetails />
<Suspense fallback={<Loading />}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// This will suspend if data not ready
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
function ProfileTimeline() {
const posts = resource.posts.read();
return <Timeline posts={posts} />;
}
更多模式和模板
更详细的模板和实践示例位于 references/details.md。阅读该文件以获取完整的模式库。
评论
支持 Markdown