序
Reactで外部のAPIとやり取りする部分を作っているときなんかに、JSON形式のデータをちょっといい感じに表示したいことってありませんか。私はあります。
console.log()
でもいいですが、人に見せたいときめんどくさいですしね。
実装
以下のサンプルコードは、スタイリングをTailwindCSSに依存しているので、使ってない人は自力でスタイリングしてください。
- デバッグとかデモアプリでの使用を想定しています
- あらゆる有効なJSONでいけるかどうかは試してないです
- このサイトで生成したJSONを数パターン試しました
-
JSON.parse()
が落ちるヤツは当然ダメです - 再帰実行してるので、有効だがすごい深いJSONもダメかもしれないです
JsonPreview.tsx
import type { ElementType, ComponentPropsWithoutRef, ReactNode } from 'react';
interface Props<T extends ElementType> {
as?: T | 'div';
jsonStr: string;
}
// 入れ子用
const InnerItem = (props: {
children: ReactNode;
keyName: number | string;
}) => {
return (
<div className="flex flex-col gap-2">
<span className="rounded-lg bg-zinc-300 text-zinc-800 p-1 shadow-lg font-mono mt-2">
{props.keyName}:
</span>
<div className="ml-6 pl-2 border-l-3 border-zinc-200">
{props.children}
</div>
</div>
);
};
// 本体
export const JsonPreview = <T extends ElementType = 'div'>(
props: Props<T> & Omit<ComponentPropsWithoutRef<T>, keyof Props<T>>
) => {
const { as: Component = 'div', jsonStr, ...attributes } = props;
try {
const json = JSON.parse(jsonStr);
if (json instanceof Array) {
// 配列の場合はインデックスをキーとして表示
return json.map((item, index) => (
<InnerItem key={index} keyName={index}>
<JsonPreview
jsonStr={JSON.stringify(item)}
as={Component}
{...(attributes as any)}
/>
</InnerItem>
));
} else if (json instanceof Object) {
// オブジェクトの場合はキーとをそのまま表示
return Object.keys(json).map((key) => (
<InnerItem key={key} keyName={key}>
<JsonPreview
jsonStr={JSON.stringify(json[key])}
as={Component}
{...(attributes as any)}
/>
</InnerItem>
));
} else {
// 配列でもオブジェクトでもない場合はasで指定したコンポーネント/エレメントでレンダリングする
return <Component {...attributes}>{json}</Component>;
}
} catch (e) {
return <div>Invalid JSON</div>;
}
};
App.tsx
import { JsonPreview } from './JsonPreview';
function App() {
return (
<>
<div className="m-4">
{/*<p>タグとしてレンダリング*/}
<JsonPreview jsonStr={json} as="p" />
</div>
</>
);
}
結果
こんな感じになります。
実際の動作を見る
終わりに
型がわかってるならちゃんとJSXを書いたらいいと思いますが、実際どんなデータが入ってきてるのかよくわからんJSONを調べるときに、JSONをテキストのままレンダリング出来たら楽かなと思って作りました。
道具が増えるのはいいことです。