如何判断Bun路由模块默认导出是React函数组件还是普通函数?
问题:区分React函数组件与普通函数的最佳方法
我需要区分模块导出的是React函数组件还是普通函数。Bun采用文件路由,可根据请求路径匹配并动态导入对应模块。
假设有两个文件:
react-route.tsx:
export default () => { return <h1>hello, world</h1> }
api-route.ts:
export default () => { return Response.json({ hello: 'world' }) }
我在Bun服务器中这样导入模块:
const router = new Bun.FileSystemRouter({ style: 'nextjs', dir: './app/routes', }) const match = router.match(req) if (!match) { return new Response('404') } const route = await import(match.filePath) // 如何判断 route.default 是React函数组件还是普通函数?
如果route.default是React函数,我就调用renderToString(<route.default />)生成响应内容;如果是普通函数,则直接调用route.default()。
我尝试过使用React的isValidElement,但始终返回false。猜测是因为需要先将其包裹为标签,但如果它不是真正的React函数,这样做会引发问题。
解决方案
方法一:通过文件扩展名区分(最简单可靠)
React函数组件通常存放在.tsx或.jsx后缀的文件中,而API路由函数一般用.ts或.js。直接通过match.filePath的扩展名判断:
const isReactRoute = match.filePath.endsWith('.tsx') || match.filePath.endsWith('.jsx'); if (isReactRoute) { const html = renderToString(<route.default />); return new Response(html, { headers: { 'Content-Type': 'text/html' } }); } else { const response = await route.default(); return response; }
这种方法无需执行函数,性能高且不会有潜在报错,是最推荐的方案。
方法二:通过执行结果判断(兼容复杂场景)
如果无法通过扩展名区分,可以安全执行函数后判断返回值类型:
try { const result = await route.default(); // 判断是否为Response对象 if (result instanceof Response) { return result; } // 尝试渲染为React元素 const html = renderToString(result); return new Response(html, { headers: { 'Content-Type': 'text/html' } }); } catch (err) { // 如果执行报错,尝试作为React组件渲染 try { const html = renderToString(<route.default />); return new Response(html, { headers: { 'Content-Type': 'text/html' } }); } catch (innerErr) { return new Response('Internal Server Error', { status: 500 }); } }
方法三:给React组件添加自定义标识
在React组件上添加一个自定义属性,用于标识:
// react-route.tsx const ReactRoute = () => { return <h1>hello, world</h1>; }; ReactRoute.isReactComponent = true; export default ReactRoute;
然后在服务器中直接判断该属性:
const defaultExport = route.default; if (defaultExport.isReactComponent) { const html = renderToString(<defaultExport />); return new Response(html, { headers: { 'Content-Type': 'text/html' } }); } else { const response = await defaultExport(); return response; }
这种方法需要修改组件代码,但判断逻辑最直接。
内容的提问来源于stack exchange,提问作者jdion84
相关产品推荐
相关产品推荐

