闽公网安备 35020302035485号
注意:本文主要讨论 React 和 Next.js 团队引入的新功能。由于双方的密切合作,这里难以区分各项功能具体出自哪支团队之手。因此,下文将以“React”统一指代双方团队。
function Playlist({ name, tracks }) {
return (
<div>
<h1>{name}</h1>
<table>
<thead>
<tr>
<th>Title</th>
<th>Artist</th>
<th>Album</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
{tracks.map((track, index) => (
<tr key={index}>
<td>{track.title}</td>
<td>{track.artist}</td>
<td>{track.album}</td>
<td>{track.duration}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
但除此之外,其他的一切都随着服务端组件的出现而有所变化。数据获取不再依靠 useEffect 或者 react-query 实现;相反,我们需要在异步组件中使用 fetch:async function PlaylistFromId({ id }) {
const response = await fetch(`/api/playlists/${id}`);
if (!response.ok) {
// This will activate the closest `error.js` Error Boundary
throw new Error('Failed to fetch data');
}
const { name, tracks } = response.json();
return <Playlist name={name} tracks={tracks} />;
}
注意,这里的 fetch 函数跟浏览器 fetch 不同。React 对其进行了增强,能够自动请求重复数据删除。为什么一定要这样调整?如果我们需要在组件树中深入访问获取的数据,由于于 useContext 已在服务端组件中被禁用 ,所以无法将 fetch 放置在 React Context 当中。现在若需要在组件树内的不同点处访问获取的数据,推荐方法是在必要时执行重新获取,再通过 React 执行重复数据删除。export function AddToFavoritesButton({ id }) {
async function addToFavorites(data) {
'use server';
// 堆代码 duidaima.com
await fetch(`/api/tracks/${id}/favorites`, { method: 'POST' });
}
return (
<form action={addToFavorites}>
<button type="submit">Add to Favorites</button>
</form>
);
}
典型的 React hooks(包括 useState, useContext, useEffect)现在都会导致服务端组件出错。如果仍须使用,大家只能借助 use client escape 路由,也就是强制 React 在客户端渲染组件。请注意,这本是 Next.js 中的默认操作,但在引入服务端组件之后成了可选功能。// in app/dashboard/layout.tsx
import styles from './styles.module.css';
export default function DashboardLayout({
children,
}: {
children: React.ReactNode,
}) {
return <section className={styles.dashboard}>{children}</section>;
}
/* in app/dashboard/styles.module.css */
.dashboard {
padding: 24px;
}
那调试受了什么影响?恭喜了家人们,React DevTools 无法显示 React 服务端组件的详细信息。我们无法在浏览器中检查组件以查看它使用的具体 props 或子组件。目前,调试 React 服务端组件的唯一方式就是借助 console.log。还有更多。
这些库通通使用标准 React hooks,所以通过服务端组件调用时会出错。
M1:{"id":"./src/ClientComponent.client.js","chunks":["client1"],"name":""}
S2:"react.suspense"
J0:["$","@1",null,{"children":[["$","span",null,{"children":"Hello from server land"}],["$","$2",null,{"fallback":"Loading tweets...","children":"@3"}]]}]
M4:{"id":"./src/Tweet.client.js","chunks":["client8"],"name":""}
J3:["$","ul",null,{"children":[["$","li",null,{"children":["$","@4",null,{"tweet":{...}}}]}],["$","li",null,{"children":["$","@4",null,{"tweet":{...}}}]}]]}]
这种格式没有任何可读性,纯属具体实现。但 HTTP、JSON 和 JSX 之所以如此流行,靠的就是良好的可读性。而 React 服务端组件显然破坏了这种优势。React 服务端组件实在晦涩难懂,对大多数开发者而言都难以阅读或调试。这样设计真能提高生产力吗?还是说只会起反作用?