Reactチュートリアル:コンポーネント、フック、パフォーマンス
公開: 2022-03-11Reactチュートリアルの最初の部分で指摘したように、Reactの使用を開始するのは比較的簡単です。 Create React App(CRA)を使用して開始し、新しいプロジェクトを開始して、開発を開始します。 悲しいことに、時間の経過とともに、特にReactを初めて使用する場合は、コードの保守がかなり難しくなる状況に遭遇する可能性があります。 コンポーネントが不必要に大きくなったり、コンポーネントである可能性はあるがそうではない要素になってしまう可能性があるため、あちこちで繰り返しコードを記述してしまう可能性があります。
ここで、React開発ソリューションについて考え始めることで、Reactの旅を実際に始めようとする必要があります。
新しいアプリ、後でReactアプリケーションに変換する必要のある新しいデザインに近づくときはいつでも、最初にスケッチに含めるコンポーネント、スケッチを分離して管理しやすくする方法、および要素を決定するようにしてください。反復的(または少なくともそれらの動作)。 「将来的に役立つ」可能性のあるコードを追加しないようにしてください。魅力的かもしれませんが、その将来は到来しない可能性があり、構成可能なオプションが豊富な追加の汎用関数/コンポーネントを維持します。
また、コンポーネントがたとえば2〜3ウィンドウの高さよりも長い場合は、後で読みやすくなるため、(可能であれば)分離する価値があるかもしれません。
Reactの制御されたコンポーネントと制御されていないコンポーネント
ほとんどのアプリケーションでは、入力とユーザーとの何らかの形の対話が必要であり、ユーザーが何かを入力したり、ファイルをアップロードしたり、フィールドを選択したりできるようにします。 Reactは、制御されたコンポーネントと制御されていないコンポーネントという2つの異なる方法でユーザーとの対話を処理します。
制御されたコンポーネントの値は、その名前が示すように、ユーザーと対話する要素に値を提供することによってReactによって制御されますが、制御されていない要素はvalueプロパティを取得しません。 そのおかげで、たまたまReact状態である信頼できる唯一の情報源があるため、画面に表示されているものと現在の状態にあるものとの間に不一致はありません。 開発者は、フォームに対するユーザーの操作に応答する関数を渡す必要があります。これにより、フォームの状態が変更されます。
class ControlledInput extends React.Component { state = { value: "" }; onChange = (e) => this.setState({ value: e.target.value }); render() { return ( <input value={this.state.value} onChange={this.onChange}/> ); } }
制御されていないReactコンポーネントでは、値がどのように変化するかは気にしませんが、正確な値を知りたい場合は、refを介してアクセスするだけです。
class UncontrolledInput extends React.Component { input = React.createRef(); getValue = () => { console.log(this.input.current.value); }; render() { return ( <input ref={this.input}/> ); } }
では、どちらをいつ使用する必要がありますか? ほとんどの場合、制御されたコンポーネントが使用方法であると言えますが、いくつかの例外があります。 たとえば、Reactで制御されていないコンポーネントを使用する必要がある1つのケースは、 file
タイプの入力です。これは、その値が読み取り専用であり、プログラムで設定できないためです(ユーザーの操作が必要です)。 また、制御されたコンポーネントは読みやすく、操作しやすいと思います。 制御されたコンポーネントの検証は再レンダリングに基づいて行われ、状態を変更でき、入力に問題があることを簡単に示すことができます(たとえば、フォーマットまたは空)。
参照
refs
についてはすでに説明しました。これは、フックが16.8に登場するまで、クラスコンポーネントで利用可能だった特別な機能です。
Refsは、参照を通じてReactコンポーネントまたはDOM要素(refをアタッチするタイプに応じて)へのアクセスを開発者に与えることができます。 コードを読みにくくし、上から下へのデータフローを中断するため、これらを回避し、必須のシナリオでのみ使用することをお勧めします。 ただし、特にDOM要素で必要な場合があります(たとえば、プログラムでフォーカスを変更する場合)。 Reactコンポーネント要素にアタッチする場合、参照しているそのコンポーネント内からメソッドを自由に使用できます。 それでも、これに対処するためのより良い方法があるため、この方法は避ける必要があります(たとえば、状態を上げて関数を親コンポーネントに移動する)。
レフリーには、3つの異なる方法があります。
- 文字列リテラルを使用する(レガシーであり、避ける必要があります)、
- ref属性に設定されているコールバック関数を使用して、
-
React.createRef()
としてrefを作成し、それをクラスプロパティにバインドし、それを介してアクセスすることによって(参照はcomponentDidMountライフサイクルから利用可能になることに注意してください)。
最後に、参照が渡されない場合や、現在のコンポーネントからより深い参照要素にアクセスしたい場合があります(たとえば、内部に<input>
DOM要素を持つ<Button>
コンポーネントがあり、現在は<Row>
コンポーネント内にあり、行コンポーネントからDOMフォーカス関数を入力するためのアクセス権が必要です。ここでforwardRef
を使用します)。
参照が渡されない場合の1つは、コンポーネントで使用されている高次のコンポーネントがある場合ですref
はprop
( key
と同様)ではないため、渡されないため、その理由は非常に理解できます。コンポーネントがラップされているのではなく、 HOC
を参照している。 このような場合、引数としてpropsとrefsをReact.forwardRef
を使用できます。これをprop
に割り当てて、アクセスするコンポーネントに渡すことができます。
function withNewReference(Component) { class Hoc extends React.Component { render() { const {forwardedRef, ...props} = this.props; return <Component ref={forwardedRef} {...props}/>; } } return React.forwardRef((props, ref) => { return <Hoc {...props} forwardedRef={ref} />; }); }
エラー境界
物事が複雑になるほど、何かがうまくいかない可能性が高くなります。 そのため、エラー境界はReactの一部です。 では、それらはどのように機能しますか?
何かがうまくいかず、その親としてエラー境界がない場合、Reactアプリ全体が失敗します。 ユーザーを誤解させて間違った情報を表示するよりも、情報を表示しない方がよいですが、必ずしもアプリケーション全体をクラッシュさせて白い画面を表示する必要があるという意味ではありません。 エラー境界を使用すると、使用できる柔軟性が追加されます。 アプリ全体で使用してエラーメッセージを表示するか、一部のウィジェットで使用して単に表示しないか、代わりにそれらのウィジェットの代わりに少量の情報を表示することができます。
一部のイベントや呼び出しを処理するために作成するのは、命令型コードではなく、宣言型コードの問題のみであることに注意してください。 これらについては、通常のtry/catchアプローチを使用する必要があります。
エラー境界は、( componentDidCatch
ライフサイクルメソッドで)使用するエラーロガーに情報を送信できる場所でもあります。
class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, info) { logToErrorLogger(error, info); } render() { if (this.state.hasError) { return <div>Help, something went wrong.</div>; } return this.props.children; } }
高階コンポーネント
高階コンポーネント(HOC)は、Reactでよく言及されており、非常に人気のあるパターンであり、おそらく使用する(またはすでに使用している)パターンです。 HOCに精通している場合は、多くのライブラリwithNavigation, connect, withRouter
を見たことがあるでしょう。
HOCは、コンポーネントを引数として取り、HOCラッパーがないコンポーネントと比較して拡張機能を備えた新しいコンポーネントを返す単なる関数です。 そのおかげで、コンポーネントを強化できるいくつかの簡単に拡張可能な機能(ナビゲーションへのアクセスなど)を実現できます。 HOCは、私たちが持っているものに応じて呼び出されるいくつかの形式を取ることもできます。常に必要な唯一の引数はコンポーネントですが、追加の引数を取ることもできます。いくつかのオプション、またはconnect
のように、最初に関数を呼び出し、後で関数を返します。これは引数コンポーネントを取り、HOCを返します。
追加でき、避けるべきことがいくつかあります。
- ラッパーHOC関数の表示名を追加します(実際には、HOCコンポーネントの表示名を変更することでHOCであることがわかります)。
- レンダリングメソッド内でHOCを使用しないでください。常に再マウントして現在の状態を失うため、新しいHOCコンポーネントを作成するのではなく、既に拡張コンポーネントを使用している必要があります。
- 静的メソッドはコピーされないため、新しく作成したHOC内に静的メソッドを含める場合は、それらを自分でコピーする必要があります。
- 上記の
React.forwardRef
を使用してください。
export function importantHoc() { return (Component) => class extends React.Component { importantFunction = () => { console.log("Very Important Function"); }; render() { return ( <Component {...this.props} importantFunction={this.importantFunction} /> ); } }; }
スタイリング
スタイリングは必ずしもReact自体に関連しているわけではありませんが、いくつかの理由から言及する価値があります。
まず、通常のCSS /インラインスタイルが通常どおりここに適用され、CSSからclassName属性にクラス名を追加するだけで、正しく機能します。 インラインスタイルは、通常のHTMLスタイルとは少し異なります。 文字列はスタイルではなく、それぞれに正しい値を持つオブジェクトで渡されます。 スタイル属性もキャメルケースであるため、border-radiusはborderRadiusなどになります。
Reactは、最近CRAに統合されたCSSモジュールなど、Reactだけでなく一般的になったいくつかのソリューションを普及させたようです。ここでは、 name.modules.css
をインポートし、プロパティなどのクラスを使用してコンポーネントのスタイルを設定できます(一部のIDEたとえば、WebStormには、そのためのオートコンプリートもあります。これにより、使用可能な名前がわかります)。
Reactでも人気のあるもう1つのソリューションは、CSS-in-JS( emotion
ライブラリなど)です。 もう一度指摘しておきますが、CSSモジュールと感情(または一般的にはCSS-in-JS)はReactに限定されません。
Reactのフック
フックは、おそらく、書き直し以来、Reactへの最も待望の追加です。 製品は誇大宣伝に応えていますか? 私の観点からすると、そうです、それらは本当に素晴らしい機能です。 それらは本質的に、次のような新しい機会を開く機能です。
- ローカル状態や参照などを取得できなかったためにのみ使用した多くの
class
コンポーネントを削除できるため、コンポーネントのコードが読みやすくなります。 - 同じ効果のために使用するコードを減らすことができます。
- たとえば、react-testing-libraryを使用することで、関数の検討とテストがはるかに簡単になります。
- パラメータを取ることもでき、その結果を別のフックで簡単に使用できます(たとえば、
setState
のuseEffect
からuseState
)。 - ミニファイアにとって少し問題になる傾向があるクラスよりもはるかに優れたミニニゼーション。
- 他の問題を解決するように設計されているにもかかわらず、新しい問題を引き起こしたHOCを削除し、アプリの小道具パターンをレンダリングする可能性があります。
- 熟練したReact開発者がカスタムビルドすることができます。
デフォルトとして含まれているReactフックはほとんどありません。 3つの基本的なものは、 useState
、 useEffect
、およびuseContext
です。 useRef
やuseMemo
など、いくつかの追加のものもありますが、ここでは基本に焦点を当てます。
useState
を見て、それを使用して単純なカウンターの例を作成しましょう。 それはどのように機能しますか? さて、基本的に、全体の構成は本当に簡単で、次のようになります。
export function Counter() { const [counter, setCounter] = React.useState(0); return ( <div> {counter} <button onClick={() => setCounter(counter + 1)}>+</button> </div> ); };
initialState
(value)で呼び出され、2つの要素を含む配列を返します。 配列の非構造化割り当てのおかげで、これらの要素に変数をすぐに割り当てることができます。 最初の状態は常に更新後の最後の状態であり、もう1つは値を更新するために使用する関数です。 簡単そうですね。
また、このようなコンポーネントは以前はステートレス機能コンポーネントと呼ばれていたため、上記のような状態になる可能性があるため、このような名前は適切ではなくなりました。 したがって、クラスコンポーネントと関数コンポーネントの名前は、少なくとも16.8.0以降、実際に行われていることとより一致しているように見えます。
更新関数(この場合はsetCounter
)は、次の形式で前の値を引数として取る関数としても使用できます。
<button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button> <button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button>
ただし、浅いマージを行っていたthis.setState
クラスコンポーネントとは異なり、関数(この場合はsetCounter
)を設定すると、代わりに状態全体がオーバーライドされます。

さらに、 initialState
は、単なる値ではなく、関数にすることもできます。 これには独自の利点があります。この関数はコンポーネントの最初のレンダリング中にのみ実行され、その後は呼び出されなくなります。
const [counter, setCounter] = useState(() => calculateComplexInitialValue());
最後に、現在の状態( counter
)で同じ瞬間に持っていたのとまったく同じ値でsetCounter
を使用する場合、コンポーネントは再レンダリングされません。
一方、 useEffect
は、サブスクリプション、API呼び出し、タイマーなど、機能コンポーネントに副作用を追加することを目的としています。 useEffect
に渡す関数はすべてレンダリング後に実行され、関数の2番目の引数として再実行する必要があるプロパティの変更に関する制限を追加しない限り、レンダリングのたびに実行されます。 マウント時にのみ実行し、アンマウント時にクリーンアップする場合は、空の配列を渡すだけです。
const fetchApi = async () => { const value = await fetch("https://jsonplaceholder.typicode.com/todos/1"); console.log(await value.json()); }; export function Counter() { const [counter, setCounter] = useState(0); useEffect(() => { fetchApi(); }, []); return ( <div> {counter} <button onClick={() => setCounter(prevCounter => prevCounter + 1)}>+</button> <button onClick={() => setCounter(prevCounter => prevCounter - 1)}>-</button> </div> ); };
上記のコードは、2番目の引数として配列が空であるため、1回だけ実行されます。 基本的には、このような場合はcomponentDidMount
のようなものですが、少し遅れて起動します。 ブラウザのペイントの前に呼び出される同様のフックが必要な場合は、 useLayoutEffect
を使用しますが、 useEffect
とは異なり、これらの更新は同期的に適用されます。
useContext
は、アクセスを取得するコンテキスト( createContext
関数によって返されたオブジェクト)を提供し、その代わりにそのコンテキストの値を提供するため、最も理解しやすいようです。
const context = useContext(Context);
最後に、独自のフックを作成するには、次のように作成します。
function useWindowWidth() { let [windowWidth, setWindowWidth] = useState(window.innerWidth); function handleResize() { setWindowWidth(window.innerWidth); } useEffect(() => { window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return windowWidth; }
基本的に、初期値ウィンドウ幅として割り当てている通常のuseState
フックを使用しています。 次に、 useEffect,
ウィンドウのサイズ変更ごとにhandleResize
をトリガーするリスナーを追加します。 コンポーネントがアンマウントされた後もクリアします( useEffect
のリターンを見てください)。 簡単?
注:すべてのフックでの単語の使用は重要です。 これは、Reactが何か悪いことをしていないかどうかをチェックできるようにするために使用されます。たとえば、通常のJS関数からフックを呼び出します。
タイプの確認
FlowとTypeScriptがオプションになる前に、Reactには独自の小道具チェックがありました。
PropTypesは、Reactコンポーネントによって受信されたプロパティ(props)をチェックし、それらが私たちが持っているものと一致しているかどうかをチェックします。 別の状況が発生するたびに(たとえば、配列ではなくオブジェクト)、コンソールに警告が表示されます。 PropTypeは、パフォーマンスへの影響と前述のコンソール警告のため、開発モードでのみチェックされることに注意してください。
React 15.5以降、PropTypesは別のパッケージに含まれているため、個別にインストールする必要があります。 これらは、 propTypes
(サプライズ)と呼ばれる静的プロパティのプロパティに沿って宣言され、プロパティが未定義の場合に使用されるdefaultProps
と組み合わされます(未定義が唯一のケースです)。 DefaultPropsはPropTypesとは関係ありませんが、PropTypesが原因で表示される可能性のあるいくつかの警告を解決できます。
他の2つのオプションはFlowとTypeScriptであり、最近でははるかに人気があります(特にTypeScript)。
- TypeScriptは、Microsoftによって開発されたJavaScriptの型付きスーパーセットであり、アプリが実行される前にエラーをチェックでき、開発用の優れたオートコンプリート機能を提供します。 また、リファクタリングも大幅に改善されます。 型付き言語の豊富な経験を持つMicrosoftのサポートにより、これもかなり安全な選択です。
- TypeScriptとは異なり、フローは言語ではありません。 これはJavaScriptの静的型チェッカーであるため、言語というよりもJavaScriptに含めるツールに似ています。 Flowの背後にある全体的な考え方は、TypeScriptが提供するものと非常に似ています。 タイプを追加できるため、コードを実行する前にバグが発生する可能性が低くなります。 TypeScriptと同様に、フローは最初からCRA(Create React App)でサポートされるようになりました。
個人的には、TypeScriptの方が速く(実際には瞬時に)、特にオートコンプリートでは、Flowでは少し遅いように見えます。 私が個人的に使用しているWebStormなどのIDEは、Flowとの統合にCLIを採用していることは注目に値します。 ただし、オプションの使用をファイルに統合する方がさらに簡単なようです。ファイルの先頭に// @flow
を追加するだけで、型チェックを開始できます。 また、私が知る限り、TypeScriptは最終的にFlowとの戦いに勝ったようです。現在でははるかに人気があり、最も人気のあるライブラリのいくつかはFlowからTypeScriptにリファクタリングされています。
Reason(Facebookによって開発され、Reactコミュニティで人気を博している)、Kotlin(JetBrainsによって開発された言語)など、公式ドキュメントにも記載されているオプションがいくつかあります。
明らかに、フロントエンド開発者にとって最も簡単なアプローチは、KotlinまたはF#に切り替えるのではなく、フローとTypeScriptを使用して開始することです。 ただし、フロントエンドに移行するバックエンド開発者にとっては、実際にはこれらの開発者の方が使い始めるのが簡単な場合があります。
生産と反応性能
本番モードで行う必要のある最も基本的で明白な変更は、DefinePluginの「本番」に切り替えて、 UglifyJsPlugin
の場合はDefinePlugin
を追加することです。 CRAの場合、 npm run build
( react-scripts build
実行します)を使用するのと同じくらい簡単です。 Brunchなどの他のビルドツールを使用できるため、WebpackとCRAだけがオプションではないことに注意してください。 これは通常、公式のReactドキュメントであれ、特定のツールのドキュメントであれ、公式のドキュメントでカバーされています。 モードが正しく設定されていることを確認するために、React Developer Toolsを使用できます。これにより、使用しているビルドの種類(本番環境と開発環境)がわかります。 前述の手順により、Reactからのチェックや警告なしでアプリケーションが実行され、バンドル自体も最小化されます。
Reactアプリでできることは他にもいくつかあります。 ビルドされたJSファイルをどうしますか? サイズが比較的小さい場合は「bundle.js」から始めるか、「ベンダー+バンドル」、「ベンダー+必要最小限のパーツ+必要なときにインポートする」などの操作を行うことができます。 これは、非常に大きなアプリを扱っていて、最初からすべてをインポートする必要がない場合に便利です。 使用されていないJavaScriptコードをメインバンドルにバンドルすると、バンドルサイズが大きくなり、最初はアプリの読み込みが遅くなることに注意してください。
ベンダーバンドルは、ライブラリのバージョンが長期間変更されない可能性があることに気付いたときに、ライブラリのバージョンをフリーズすることを計画している場合に役立ちます。 また、ファイルが大きいほどgzipがうまくいくため、分離することで得られるメリットが価値がない場合があります。 ファイルサイズによって異なりますが、自分で試してみる必要がある場合もあります。
コード分割
コード分割は、ここで提案されているよりも多くの方法で表示される可能性がありますが、CRAとReact自体で利用できるものに焦点を当てましょう。 基本的に、コードを異なるチャンクに分割するために、Webpackのおかげで機能するimport()
を使用できます( import
自体は現在ステージ3での提案であるため、まだ言語標準の一部ではありません)。 Webpackがimport
を確認するたびに、この段階でコード分割を開始する必要があり、メインバンドル(インポート内にあるコード)に含めることができないことがわかります。
これで、その場所でレンダリングする必要のあるコンポーネントを含むファイルパスを使用してimport()
React.lazy()
に接続できます。 次に、 React.suspense()
を使用して、インポートされたコンポーネントが読み込まれるまで、その場所に別のコンポーネントを表示できます。 不思議に思うかもしれません。 単一のコンポーネントをインポートする場合、なぜそれが必要になるのでしょうか。
React.lazy()
はimport()
のコンポーネントを表示するので、そうではありませんが、 import()
はその単一のコンポーネントよりも大きなチャンクをフェッチする可能性があります。 たとえば、その特定のコンポーネントには、他のライブラリが含まれている場合や、コードが多い場合など、1つのファイルは必要ありません。さらに多くのファイルがバンドルされている場合があります。 最後に、それらすべてをErrorBoundary
でラップできます(エラー境界のセクションにコードがあります) 。これは、インポートしたいコンポーネントで何かが失敗した場合(たとえば、ネットワークエラーがある場合)のフォールバックとして機能します。
import ErrorBoundary from './ErrorBoundary'; const ComponentOne = React.lazy(() => import('./ComponentOne')); function MyComponent() { return ( <ErrorBoundary> <React.Suspense fallback={<div>Loading...</div>}> <ComponentOne/> </React.Suspense> </ErrorBoundary> ); }
これは基本的な例ですが、明らかにもっと多くのことができます。 import
とReact.lazy
を使用して、動的なルート分割を行うことができます(たとえば、管理者と通常のユーザー、または多くをもたらす非常に大きなパス)。 React.lazy
は現在、デフォルトのエクスポートのみをサポートしており、サーバー側のレンダリングはサポートしていないことに注意してください。
Reactコードのパフォーマンス
パフォーマンスに関しては、Reactアプリケーションの動作が遅い場合、問題を理解するのに役立つ2つのツールがあります。
1つ目はChromeの[パフォーマンス]タブで、各コンポーネント(マウント、更新など)で何が起こるかを示します。 そのおかげで、どのコンポーネントがパフォーマンスの問題の問題を示しているかを特定し、それを最適化できるはずです。
もう1つのオプションは、React16.5以降で利用可能になったDevToolsProfilerを使用することです。また、shouldComponentUpdate(またはこのチュートリアルのパート1で説明したPureComponent)の協力を得て、いくつかの重要なコンポーネントのパフォーマンスを向上させることができます。
明らかに、一部のイベント(スクロールなど)のデバウンス、アニメーション(高さを変更してアニメーション化する代わりに変換を使用)に注意するなど、Webの基本的なベストプラクティスを採用するのが最適です。 特にReactを理解し始めたばかりの場合は、ベストプラクティスの使用は非常に簡単に見落とされる可能性があります。
2019年以降のReactの状態
Reactの将来について個人的に話し合うのであれば、私はあまり心配しません。 私の見解では、Reactは2019年以降も問題なく王位を維持できます。
Reactは非常に強力な立場にあり、大規模なコミュニティの支持を受けているため、王位を奪うことは困難です。 Reactコミュニティは素晴らしく、アイデアが不足することはありません。コアチームは、Reactの改善、新機能の追加、古い問題の修正に絶えず取り組んでいます。 Reactも巨大な会社に支えられていますが、ライセンスの問題はなくなりました。現在MITライセンスです。
はい、変更または改善が期待されることがいくつかあります。 たとえば、Reactを少し小さくする(言及された手段の1つは、合成イベントを削除することです)、またはclassName
の名前をclass.
もちろん、これらの一見小さな変更でさえ、ブラウザの互換性に影響を与えるなどの問題を引き起こす可能性があります。 個人的には、WebComponentの人気が高まるとどうなるのだろうかと思います。これは、Reactが今日よく使用されているもののいくつかを補強する可能性があるためです。 それらが完全に置き換わるものになるとは思いませんが、互いにうまく補完し合う可能性があると思います。
短期的には、フックがReactに登場したばかりです。 これは、Reactで書き直しが行われて以来、おそらく最大の変更です。これは、多くの可能性を開き、さらに機能コンポーネントを強化するためです(そして、現在、実際に誇大宣伝されています)。
最後に、それが私が最近やっていることなので、ReactNativeがあります。 私にとって、これは過去2年間で大きく変化した優れたテクノロジーです(react-nativeリンクの欠如は、ほとんどの人にとっておそらく最大の問題であり、明らかに多くのバグがありました)。 React Nativeはコアを書き直しているので、Reactの書き直しと同様の方法で行う必要があります(これはすべて内部的なものであり、開発者にとっては何も変更しないか、ほとんど変更しないでください)。 非同期レンダリング、ネイティブとJavaScriptの間のより高速で軽量なブリッジなど。
Reactエコシステムには楽しみがたくさんありますが、フック(および誰かがモバイルを愛している場合はReact Native)の更新は、おそらく2019年に見られる最も重要な変更です。