npx skills add https://github.com/slanycukr/riot-api-project --skill 'React 19'React 19 引入了强大的新功能,用于构建具有增强服务器能力、改进的表单处理和更好性能的现代 Web 应用程序。
import { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Count changed:", count);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
import { useState, useEffect } from "react";
function useApiData(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Usage
function UserProfile({ userId }) {
const { data: user, loading, error } = useApiData(`/api/users/${userId}`);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!user) return <div>No user found</div>;
return <div>{user.name}</div>;
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// Server action
"use server";
async function updateUser(formData) {
const name = formData.get("name");
const email = formData.get("email");
// Database update logic here
await db.users.update({ name, email });
return { success: true, message: "User updated successfully" };
}
// Client component with form
function UserForm({ user }) {
const [state, formAction, isPending] = useActionState(updateUser, null);
return (
<form action={formAction}>
<input name="name" defaultValue={user.name} />
<input name="email" defaultValue={user.email} />
<button type="submit" disabled={isPending}>
{isPending ? "Updating..." : "Update"}
</button>
{state?.message && <p>{state.message}</p>}
</form>
);
}
import { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button>
);
}
function ContactForm() {
return (
<form action={submitContact}>
<input name="name" placeholder="Your name" />
<input name="email" placeholder="Your email" />
<SubmitButton />
</form>
);
}
// Server Component (runs on server)
async function BlogPost({ id }) {
const post = await db.posts.find(id);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
<CommentSection postId={post.id} />
</article>
);
}
// Client Component for interactivity
("use client");
function CommentSection({ postId }) {
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState("");
const addComment = async () => {
// Client-side logic for adding comments
};
return (
<div>
<h3>Comments</h3>
{/* Comment rendering and form */}
</div>
);
}
import { createContext, useContext, useState, useReducer } from "react";
// Create context
const AuthContext = createContext();
// Auth provider component
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = async (credentials) => {
// Login logic
setUser(userData);
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
// Custom hook for consuming context
function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
}
// Usage in components
function Header() {
const { user, logout } = useAuth();
return (
<header>
{user ? (
<div>
<span>Welcome, {user.name}</span>
<button onClick={logout}>Logout</button>
</div>
) : (
<div>Please log in</div>
)}
</header>
);
}
import { Suspense } from "react";
// Async component
async function UserList() {
const users = await fetchUsers(); // async function
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// Using Suspense boundary
function App() {
return (
<div>
<h1>Users</h1>
<Suspense fallback={<div>Loading users...</div>}>
<UserList />
</Suspense>
</div>
);
}
import { useState, useTransition } from "react";
function TodoList() {
const [todos, setTodos] = useState(initialTodos);
const [isPending, startTransition] = useTransition();
const addTodo = async (newTodo) => {
// Optimistic update
const optimisticId = Date.now();
startTransition(() => {
setTodos((prev) => [
...prev,
{
id: optimisticId,
text: newTodo,
status: "optimistic",
},
]);
});
try {
const savedTodo = await saveTodo(newTodo);
// Replace optimistic todo with saved one
setTodos((prev) =>
prev.map((todo) => (todo.id === optimisticId ? savedTodo : todo)),
);
} catch (error) {
// Revert optimistic update on error
setTodos((prev) => prev.filter((todo) => todo.id !== optimisticId));
}
};
return (
<div>
<ul>
{todos.map((todo) => (
<li
key={todo.id}
style={{ opacity: todo.status === "optimistic" ? 0.5 : 1 }}
>
{todo.text}
</li>
))}
</ul>
<button onClick={() => addTodo("New task")} disabled={isPending}>
Add Todo
</button>
</div>
);
}
import { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error("Error caught by boundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong</h2>
<details>{this.state.error?.message}</details>
</div>
);
}
return this.props.children;
}
}
// Usage
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
import { useState, useMemo, useCallback } from "react";
function ExpensiveComponent({ data, onItemClick }) {
const [filter, setFilter] = useState("");
// Memoize expensive computation
const filteredData = useMemo(() => {
console.log("Filtering data...");
return data.filter((item) =>
item.name.toLowerCase().includes(filter.toLowerCase()),
);
}, [data, filter]);
// Memoize event handler
const handleItemClick = useCallback(
(item) => {
onItemClick(item);
},
[onItemClick],
);
return (
<div>
<input
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder="Filter items..."
/>
<ul>
{filteredData.map((item) => (
<li key={item.id} onClick={() => handleItemClick(item)}>
{item.name}
</li>
))}
</ul>
</div>
);
}
import { lazy, Suspense } from "react";
// Lazy load component
const AdminDashboard = lazy(() => import("./AdminDashboard"));
function App() {
const [isAdmin, setIsAdmin] = useState(false);
return (
<div>
<h1>My App</h1>
<button onClick={() => setIsAdmin(true)}>Admin View</button>
{isAdmin && (
<Suspense fallback={<div>Loading admin dashboard...</div>}>
<AdminDashboard />
</Suspense>
)}
</div>
);
}
// Good: Single responsibility components
function UserAvatar({ user, size = "medium" }) {
return (
<img
src={user.avatar}
alt={user.name}
className={`avatar avatar-${size}`}
/>
);
}
function UserCard({ user }) {
return (
<div className="user-card">
<UserAvatar user={user} size="large" />
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
import PropTypes from "prop-types";
function Button({
children,
variant = "primary",
size = "medium",
onClick,
disabled = false,
}) {
const className = `btn btn-${variant} btn-${size}`;
return (
<button className={className} onClick={onClick} disabled={disabled}>
{children}
</button>
);
}
Button.propTypes = {
children: PropTypes.node.isRequired,
variant: PropTypes.oneOf(["primary", "secondary", "danger"]),
size: PropTypes.oneOf(["small", "medium", "large"]),
onClick: PropTypes.func,
disabled: PropTypes.bool,
};
npm install react@19 react-dom@19
npm install --save-dev @types/react @types/react-dom
zustand, jotai, 或 Context APIreact-router-dom@tanstack/react-queryreact-hook-formtailwindcss, styled-components, 或 CSS 模块每周安装次数
–
代码仓库
GitHub 星标数
2
首次出现
–
安全审计
React 19 introduces powerful new features for building modern web applications with enhanced server capabilities, improved form handling, and better performance.
import { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Count changed:", count);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
import { useState, useEffect } from "react";
function useApiData(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Usage
function UserProfile({ userId }) {
const { data: user, loading, error } = useApiData(`/api/users/${userId}`);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!user) return <div>No user found</div>;
return <div>{user.name}</div>;
}
// Server action
"use server";
async function updateUser(formData) {
const name = formData.get("name");
const email = formData.get("email");
// Database update logic here
await db.users.update({ name, email });
return { success: true, message: "User updated successfully" };
}
// Client component with form
function UserForm({ user }) {
const [state, formAction, isPending] = useActionState(updateUser, null);
return (
<form action={formAction}>
<input name="name" defaultValue={user.name} />
<input name="email" defaultValue={user.email} />
<button type="submit" disabled={isPending}>
{isPending ? "Updating..." : "Update"}
</button>
{state?.message && <p>{state.message}</p>}
</form>
);
}
import { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button>
);
}
function ContactForm() {
return (
<form action={submitContact}>
<input name="name" placeholder="Your name" />
<input name="email" placeholder="Your email" />
<SubmitButton />
</form>
);
}
// Server Component (runs on server)
async function BlogPost({ id }) {
const post = await db.posts.find(id);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
<CommentSection postId={post.id} />
</article>
);
}
// Client Component for interactivity
("use client");
function CommentSection({ postId }) {
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState("");
const addComment = async () => {
// Client-side logic for adding comments
};
return (
<div>
<h3>Comments</h3>
{/* Comment rendering and form */}
</div>
);
}
import { createContext, useContext, useState, useReducer } from "react";
// Create context
const AuthContext = createContext();
// Auth provider component
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = async (credentials) => {
// Login logic
setUser(userData);
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
// Custom hook for consuming context
function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
}
// Usage in components
function Header() {
const { user, logout } = useAuth();
return (
<header>
{user ? (
<div>
<span>Welcome, {user.name}</span>
<button onClick={logout}>Logout</button>
</div>
) : (
<div>Please log in</div>
)}
</header>
);
}
import { Suspense } from "react";
// Async component
async function UserList() {
const users = await fetchUsers(); // async function
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// Using Suspense boundary
function App() {
return (
<div>
<h1>Users</h1>
<Suspense fallback={<div>Loading users...</div>}>
<UserList />
</Suspense>
</div>
);
}
import { useState, useTransition } from "react";
function TodoList() {
const [todos, setTodos] = useState(initialTodos);
const [isPending, startTransition] = useTransition();
const addTodo = async (newTodo) => {
// Optimistic update
const optimisticId = Date.now();
startTransition(() => {
setTodos((prev) => [
...prev,
{
id: optimisticId,
text: newTodo,
status: "optimistic",
},
]);
});
try {
const savedTodo = await saveTodo(newTodo);
// Replace optimistic todo with saved one
setTodos((prev) =>
prev.map((todo) => (todo.id === optimisticId ? savedTodo : todo)),
);
} catch (error) {
// Revert optimistic update on error
setTodos((prev) => prev.filter((todo) => todo.id !== optimisticId));
}
};
return (
<div>
<ul>
{todos.map((todo) => (
<li
key={todo.id}
style={{ opacity: todo.status === "optimistic" ? 0.5 : 1 }}
>
{todo.text}
</li>
))}
</ul>
<button onClick={() => addTodo("New task")} disabled={isPending}>
Add Todo
</button>
</div>
);
}
import { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
console.error("Error caught by boundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong</h2>
<details>{this.state.error?.message}</details>
</div>
);
}
return this.props.children;
}
}
// Usage
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
import { useState, useMemo, useCallback } from "react";
function ExpensiveComponent({ data, onItemClick }) {
const [filter, setFilter] = useState("");
// Memoize expensive computation
const filteredData = useMemo(() => {
console.log("Filtering data...");
return data.filter((item) =>
item.name.toLowerCase().includes(filter.toLowerCase()),
);
}, [data, filter]);
// Memoize event handler
const handleItemClick = useCallback(
(item) => {
onItemClick(item);
},
[onItemClick],
);
return (
<div>
<input
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder="Filter items..."
/>
<ul>
{filteredData.map((item) => (
<li key={item.id} onClick={() => handleItemClick(item)}>
{item.name}
</li>
))}
</ul>
</div>
);
}
import { lazy, Suspense } from "react";
// Lazy load component
const AdminDashboard = lazy(() => import("./AdminDashboard"));
function App() {
const [isAdmin, setIsAdmin] = useState(false);
return (
<div>
<h1>My App</h1>
<button onClick={() => setIsAdmin(true)}>Admin View</button>
{isAdmin && (
<Suspense fallback={<div>Loading admin dashboard...</div>}>
<AdminDashboard />
</Suspense>
)}
</div>
);
}
// Good: Single responsibility components
function UserAvatar({ user, size = "medium" }) {
return (
<img
src={user.avatar}
alt={user.name}
className={`avatar avatar-${size}`}
/>
);
}
function UserCard({ user }) {
return (
<div className="user-card">
<UserAvatar user={user} size="large" />
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
import PropTypes from "prop-types";
function Button({
children,
variant = "primary",
size = "medium",
onClick,
disabled = false,
}) {
const className = `btn btn-${variant} btn-${size}`;
return (
<button className={className} onClick={onClick} disabled={disabled}>
{children}
</button>
);
}
Button.propTypes = {
children: PropTypes.node.isRequired,
variant: PropTypes.oneOf(["primary", "secondary", "danger"]),
size: PropTypes.oneOf(["small", "medium", "large"]),
onClick: PropTypes.func,
disabled: PropTypes.bool,
};
npm install react@19 react-dom@19
npm install --save-dev @types/react @types/react-dom
zustand, jotai, or Context APIreact-router-dom@tanstack/react-queryreact-hook-formtailwindcss, styled-components, or CSS modulesWeekly Installs
–
Repository
GitHub Stars
2
First Seen
–
Security Audits
Vue.js测试最佳实践:Vue 3组件、组合式函数、Pinia与异步测试完整指南
3,800 周安装