
next.js 13 的 server components 不支持 `useselector` 等 react hooks,而 `async` 组件会被自动视为服务端组件;若需在客户端使用 redux 状态和异步逻辑,必须改用 `useeffect` + `usestate` 模式,并确保组件标记为 `"use client"`。
在 Next.js 13 中,async 函数不能直接作为客户端组件(Client Component)使用——一旦组件被声明为 async,React(及 Next.js 编译器)会将其识别为 Server Component,从而禁止调用任何客户端 Hook(如 useSelector、useState、useEffect),导致报错:Cannot read properties of null (reading 'useContext')。
✅ 正确做法是:
- 移除组件的 async 声明,保持其为普通函数组件;
- 使用 useEffect 触发异步请求,配合 useState 管理加载状态与数据;
- 确保顶部已添加 "use client" 指令(你已正确添加);
- 在 useEffect 内部访问 Redux 状态(注意:useSelector 可在 useEffect 中安全调用,但其返回值不可用于服务端渲染逻辑)。
以下是修正后的完整示例:
"use client";
import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import axios from "axios";
import SearchResults from "./searchResults";
const SearchRecipe = () => {
const [recipes, setRecipes] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// ✅ 正确:在 useEffect 中读取 Redux 状态 + 发起请求
useEffect(() => {
const fetchRecipes = async () => {
try {
setLoading(true);
// ? 可选:根据 Redux 中的 searchTerm 动态构造请求
const searchTerm = useSelector((state) => state.recipe.value.searchTerm) || "cake";
const response = await axios.get(
`https://api.edamam.com/api/recipes/v2?type=public&q=${encodeURIComponent(searchTerm)}&app_id=API_ID&app_key=API_KEY`
);
setRecipes(response.data);
} catch (err) {
console.error("Failed to fetch recipes:", err);
setError(err.message);
} finally {
setLoading(false);
}
};
fetchRecipes();
}, []); // ⚠️ 注意:useSelector 依赖项不建议直接写进 deps 数组(会引发警告),如需响应 search term 变化,请用 useCallback 或额外 useEffect 监听
if (loading) return Loading...;
if (error) return Error: {error};
if (!recipes) return null;
return (
);
};
export default SearchRecipe;? 关键注意事项:
- ❌ 不要写 const SearchRecipe = async () => { ... } —— 这会让组件变成 Server Component,彻底禁用所有 Hooks;
- ✅ useSelector 必须在客户端组件的渲染函数或 useEffect 中调用,不能在顶层异步函数中直接使用;
- ? 若需响应 searchTerm 变更重新请求(例如用户输入后搜索),应将 searchTerm 加入 useEffect 依赖数组,并配合防抖或提交触发机制,避免频繁请求;
- ?️ 生产环境请务必替换 API_ID 和 API_KEY,并考虑将 API 调用封装到自定义 Hook(如 useRecipes)中以提升可复用性与测试性。
遵循以上模式,即可在 Next.js 13 的 App Router 中稳定、高效地结合 Redux Toolkit 与异步数据流。










