ヘルプ
サポート

Preact アプリのデバッグ

Preact には、デバッグを容易にするためのツールが多数付属しています。これらは単一のインポートにパッケージ化されており、preact/debug をインポートすることで含めることができます。

これらには、Chrome と Firefox 用の独自の Preact Devtools 拡張機能との統合が含まれています。

<table> 要素のネストが正しくないなど、問題が検出された場合は、警告またはエラーが表示されます。



インストール

Preact Devtools は、ブラウザの拡張ストアからインストールできます。

インストールが完了したら、拡張機能への接続を初期化するために、どこかに `preact/debug` をインポートする必要があります。このインポートがアプリ全体で**最初の**インポートであることを確認してください。

preact-cli は `preact/debug` パッケージを自動的に含んでいます。使用している場合は、次の手順を安全にスキップできます。

アプリケーションのメインエントリファイルは、次のようになります。

// Must be the first import
import "preact/debug";
import { render } from 'preact';
import App from './components/App';

render(<App />, document.getElementById('root'));

本番環境から devtools を削除する

ほとんどのバンドラーは、`if` 文の中の分岐に到達しないことが検出された場合、コードを取り除くことができます。これを使用して、開発中にのみ `preact/debug` を含め、本番ビルドで貴重なバイト数を節約できます。

// Must be the first import
if (process.env.NODE_ENV==='development') {
  // Must use require here as import statements are only allowed
  // to exist at top-level.
  require("preact/debug");
}

import { render } from 'preact';
import App from './components/App';

render(<App />, document.getElementById('root'));

ビルドツールで `NODE_ENV` 変数を正しい値に設定してください。

デバッグの警告とエラー

Preact が無効なコードを検出した場合、警告またはエラーが表示されることがあります。アプリが正常に動作することを確認するために、これらを修正する必要があります。

`render()` に `undefined` の親が渡されました

これは、コードが DOM ノードではなく、何もない場所にアプリをレンダリングしようとしていることを意味します。違いは次のとおりです。

// What Preact received
render(<App />, undefined);

// vs what it expected
render(<App />, actualDomNode);

このエラーが発生する主な理由は、`render()` 関数が呼び出されたときに DOM ノードが存在しないことです。それが存在することを確認してください。

`createElement()` に `undefined` のコンポーネントが渡されました

コンポーネントの代わりに `undefined` を渡すと、Preact はこのエラーをスローします。このエラーの一般的な原因は、`default` エクスポートと `named` エクスポートを混同することです。

// app.js
export default function App() {
  return <div>Hello World</div>;
}

// index.js: Wrong, because `app.js` doesn't have a named export
import { App } from './app';
render(<App />, dom);

逆の場合も、同じエラーがスローされます。`named` エクスポートを宣言し、それを `default` エクスポートとして使用しようとすると、エラーが発生します。これをチェックする簡単な方法の 1 つは (エディタがまだ行っていない場合)、インポートをログ出力することです。

// app.js
export function App() {
  return <div>Hello World</div>;
}

// index.js
import App from './app';

console.log(App);
// Logs: { default: [Function] } instead of the component

JSX リテラルが JSX として 2 回渡されました

JSX リテラルまたはコンポーネントを JSX に再度渡すのは無効であり、このエラーが発生します。

const Foo = <div>foo</div>;
// Invalid: Foo already contains a JSX-Element
render(<Foo />, dom);

これを修正するには、変数を直接渡すだけです。

const Foo = <div>foo</div>;
render(Foo, dom);

テーブルのネストが不正です

HTML には、テーブルの構造化方法に関する明確な指示があります。それから逸脱すると、デバッグが非常に困難なレンダリングエラーが発生します。Preact ではこれを検出してエラーを出力します。テーブルの構造化方法の詳細については、mdn のドキュメント をお勧めします。

無効な `ref` プロパティ

`ref` プロパティに予期しないものが含まれている場合、このエラーがスローされます。これには、しばらく前に非推奨となった文字列ベースの `ref` が含まれます。

// valid
<div ref={e => {/* ... */)}} />

// valid
const ref = createRef();
<div ref={ref} />

// Invalid
<div ref="ref" />

無効なイベントハンドラ

誤った値をイベントハンドラに渡してしまうことがあります。それらは常に `function` であるか、削除する場合は `null` である必要があります。他のすべての型は無効です。

// valid
<div onClick={() => console.log("click")} />

// invalid
<div onClick={console.log("click")} />

フックはレンダリングメソッドからのみ呼び出すことができます

このエラーは、コンポーネントの外部でフックを使用しようとすると発生します。フックは関数コンポーネント内でのみサポートされています。

// Invalid, must be used inside a component
const [value, setValue] = useState(0);

// valid
function Foo() {
  const [value, setValue] = useState(0);
  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

`vnode.[property]` の取得は非推奨です

Preact X では、内部 `vnode` の形状に破壊的な変更を加えました。

Preact 8.xPreact 10.x
vnode.nodeNamevnode.type
vnode.attributesvnode.props
vnode.childrenvnode.props.children

同じキーを持つ子が検出されました

仮想 DOM ベースのライブラリのユニークな点の 1 つは、子が移動されたときを検出する必要があることです。ただし、どの子供がどれであるかを知るためには、何らかの方法でそれらにフラグを付ける必要があります。*これは、子を動的に作成する場合にのみ必要です。*

// Both children will have the same key "A"
<div>
  {['A', 'A'].map(char => <p key={char}>{char}</p>)}
</div>

正しい方法は、それらに一意のキーを与えることです。ほとんどの場合、反復処理しているデータには、何らかの形式の `id` があります。

const persons = [
  { name: 'John', age: 22 },
  { name: 'Sarah', age: 24}
];

// Somewhere later in your component
<div>
  {persons.map(({ name, age }) => {
    return <p key={name}>{name}, Age: {age}</p>;
  })}
</div>