コンポーネントの間違いをやめてください
実のところ、コンポーネントは一見シンプルです。始めるのは簡単です。関数を定義し、JSX を返し、それを呼び出すだけです。しかし、クリーンで保守しやすく、快適に作業できるコンポーネントを作成するにはどうすればよいでしょうか?それは全く異なる球技です。
私たちは気づかないうちに次のようなコンポーネントを作成しています。
- 大きすぎて一目では理解できません。
- テストするのは非常に難しいです。
- 非常に密接に結合されているため、再利用は不可能です。
- パフォーマンスの判断が不十分なため、停滞しています。
この投稿では、開発者が React コンポーネントで犯す最も一般的な間違いについて説明します。さらに重要なことは、アプリ全体をバラバラにせずに問題を修正する方法を説明することです。
初心者でも、何年もの経験がある場合でも、これらのヒントは、機能するだけでなく保守が楽しいコンポーネントを作成するのに役立ちます。
「すべてのコンポーネント」のアンチパターン
私たち全員が犯す古典的な失敗、つまりすべてのコンポーネントについて話しましょう。あなたも見たことがありますが、最初は小さくて無邪気で、おそらく単純なフォームまたはダッシュボードとして始まります。少し早送りすると、状態を管理し、API 呼び出しを処理し、データをフォーマットし、場合によっては朝のコーヒーを淹れることもできます。
// Please, no more of this const UserDashboard = () => { const [userData, setUserData] = useState(null); const [orders, setOrders] = useState([]); const [notifications, setNotifications] = useState([]); const [settings, setSettings] = useState({}); const [isEditing, setIsEditing] = useState(false); const [activeTab, setActiveTab] = useState('profile'); // 15 separate useEffects // 10 different event handlers // Multiple conditional renders // 300+ lines of chaos };
聞き覚えがありますか?
自分が有罪かどうかを見分ける方法
次の場合、コンポーネントは「すべてのコンポーネント」になっている可能性があります。
- 状態のオーバーロード: 3 ~ 4 つ以上の個別の状態を追跡しています。
- 際限なくスクロールする: 特定の関数やロジックを探すのに時間がかかりすぎます。
- 依存関係の肥大化: useEffect の依存関係は、毎週の買い物リストのようになります。
- 機能のクリープ拒否: 機能がもう 1 つ増えても問題ない、と自分に言い聞かせます。
ブレイク・イット・ダウン
解決策は?すべてを単一のコンポーネントにする代わりに、責任をより小さく集中した部分に分割します。
// A cleaner, smarter approach const UserDashboard = () => { return ( <div> <UserProfile /> <OrderHistory /> <NotificationCenter /> <UserSettings /> </div> ); };
重要な原則: ロジック >レイアウト
リファクタリングするときは、画面上の見た目に基づいてコンポーネントを分割しないでください。責任ごとに分けてください。この機能は独自のコンポーネントに値するか? 自問してください。ユーザー プロフィールや注文履歴など、何か別のものを処理している場合は、おそらく処理されます。
ヒント: 優れたコンポーネントは、1 つのことを適切に実行します。その目的を一文で説明するのが難しい場合は、やりすぎている可能性があります。
プロップドリル地獄
「小道具を渡す」というあまり面白くないゲームについて話しましょう。深くネストされた子に到達するためだけに同じプロップを複数のコンポーネントに渡したことがあれば、プロップドリル地獄にはまっていることになります。
// Please, no more of this const UserDashboard = () => { const [userData, setUserData] = useState(null); const [orders, setOrders] = useState([]); const [notifications, setNotifications] = useState([]); const [settings, setSettings] = useState({}); const [isEditing, setIsEditing] = useState(false); const [activeTab, setActiveTab] = useState('profile'); // 15 separate useEffects // 10 different event handlers // Multiple conditional renders // 300+ lines of chaos };
このアプローチは面倒なだけでなく、長期的な問題を引き起こします。ユーザー プロパティの名前を変更する必要があると想像してください。突然、5 か所以上で更新するようになりました。さらに悪いことに、コンポーネントを使用すらしていないデータに結び付けることになります。
これを修正する方法
小道具を使ってホットポテトをする必要はありません。ここでは、穴あけを完全に回避するための 2 つの実用的な解決策を紹介します。
1.共有データにコンテキストを使用する
アプリのさまざまな部分にまたがってデータにアクセスする場合、React の Context API を使用すると作業を簡素化できます。
// A cleaner, smarter approach const UserDashboard = () => { return ( <div> <UserProfile /> <OrderHistory /> <NotificationCenter /> <UserSettings /> </div> ); };
2.柔軟性を高めるためにコンポジションを使用する
プロップをレイヤーに強制的に通すのではなく、必要なものだけを渡すようにコンポーネントを再構築します。
// This is exhausting const App = () => { const [user, setUser] = useState({}); return ( <Layout user={user}> <Sidebar user={user}> <Navigation user={user}> <UserMenu user={user} /> </Navigation> </Sidebar> </Layout> ); };
重要なポイント
コンテキストは、ユーザー情報、テーマ、グローバル設定などのアプリ全体のデータに適しています。ただし、それが常に最善の選択肢であるとは限りません。使いすぎないでください。局所的な状態については、ドリル加工を完全に回避するようにコンポーネントの構造を調整できるかどうかを検討してください。
目標は、コンポーネントを明確にして保守しやすくすることです。小道具の穴あけを避けることで、時間、イライラ、そして将来の無数の頭痛の種を節約できます。
時期尚早な最適化の罠
時期尚早な最適化が諸悪の根源であるという有名な言葉を聞いたことがあるでしょう。さて、コンポーネントレベルの悪へようこそ。私が話しているのは、二度必要になるかどうかも分からないうちに、すべてを再利用可能にしようとするときのことです。
通常は次のようになります:
const UserContext = createContext(); const App = () => { const [user, setUser] = useState({}); return ( <UserContext.Provider value={user}> <Layout> <Sidebar> <Navigation /> </Sidebar> </Layout> </UserContext.Provider> ); }; // Use it only where needed const UserMenu = () => { const user = useContext(UserContext); return <div>{user.name}</div>; };
コンポーネントを自然に進化させましょう。今日必要とわかっているものを構築します。新しい要件が発生した場合は、明確に正当化できるときに機能を追加してください。時期尚早な最適化は時間を無駄にし、複雑さを増し、ほとんど報われません。
覚えておいてください: YAGNI 原則 (You Aren’t Gonna Need It) はコンポーネントにも適用されます。最高の抽象化は、解決しようとしている問題に実際に遭遇したときに生まれます。過剰なエンジニアリングは積極的に行われるように感じるかもしれませんが、常にシンプルさが勝利します。
副作用の不始末
これは悪影響管理の典型的な例です。
// Focused components for better clarity const Navigation = ({ children }) => { return <nav>{children}</nav>; }; // Pass data only where required const App = () => { const user = useUser(); return ( <Layout> <Navigation> <UserMenu user={user} /> </Navigation> </Layout> ); };
よくある間違いと修正
1) 面倒なデータの取得
不適切なデータ処理は、解決するよりも多くのバグを生み出します。これはよりクリーンなアプローチです:
// Behold, the over-engineered button const Button = ({ children, variant = 'primary', size = 'medium', isFullWidth = false, isDisabled = false, isLoading = false, leftIcon, rightIcon, onClick, customClassName, style, loadingText = 'Loading...', tooltipText, animationType, // ... 10 more props }) => { // 50 lines of prop processing logic return ( <button className={generateComplexClassNames()} > <h3> Why This Hurts </h3> <ul> <li>Your “simple” button now requires an instruction manual.</li> <li>Most of those 15+ props will never be used.</li> <li>Making updates becomes risky because you have to account for endless combinations.</li> <li>Writing tests becomes painful, with a hundred possible scenarios to consider.</li> </ul> <h3> Better Approach: </h3> <p>Instead of building for every imaginable scenario, start small and let your components grow as needed.<br> </p> <pre class="brush:php;toolbar:false">// Start simple const Button = ({ children, onClick, variant = 'primary' }) => { return ( <button className={`btn btn-${variant}`} onClick={onClick} > {children} </button> ); } // Create specific buttons when you actually need them const LoadingButton = ({ isLoading, children, ...props }) => { return ( <Button {...props}> {isLoading ? 'Loading...' : children} </Button> ); }
2) クリーンアップを忘れる
後は必ず片付けてください:
const UserProfile = ({ userId }) => { const [user, setUser] = useState(null); const [posts, setPosts] = useState([]); // Dependency array woes useEffect(() => { fetchUserData(userId); fetchUserPosts(userId); // No cleanup? Yikes. }, []); // eslint-disable-line react-hooks/exhaustive-deps // Multiple effects, all tangled useEffect(() => { const subscription = subscribeToUserStatus(userId); }, [userId]); // Cleanup? What cleanup? useEffect(() => { const interval = setInterval(checkNotifications, 5000); }, []); };
3) 競合状態の無視
この手法を使用してリクエストの重複を避けます:
// Improved version const UserProfile = ({ userId }) => { const { data: user, isLoading } = useQuery( ['user', userId], () => fetchUserData(userId) ); // Keep concerns separate const { data: posts } = useQuery( ['posts', userId], () => fetchUserPosts(userId), { enabled: !!user } ); };
簡単なヒント
- useEffect を使用する前に考えてください: 場合によっては、useEffect がまったく必要ない場合もあります。
- 焦点を絞ってください: 1 つのエフェクトで 1 つの責任を処理する必要があります。
- 常にクリーンアップ: サブスクリプション、間隔、イベント リスナーには注意が必要です。
- 適切なツールを使用します。React Query のようなライブラリを使用すると、データのフェッチとキャッシュが簡素化されます。
- eslint-disable で不正行為をしないでください。依存関係の問題を非表示にするのではなく、修正してください。
パフォーマンスの盲点
これらの卑劣なパフォーマンスの問題について話しましょう。彼らは、すべてがうまくいっているように見えるため、実際はそうではないときまで、目立たないように行動するタイプです。これらの静かな犯人を明らかにし、それらを修正する方法を見てみましょう。
問題
ここでは、パフォーマンスに微妙な落とし穴があるコンポーネントを示します。
// Please, no more of this const UserDashboard = () => { const [userData, setUserData] = useState(null); const [orders, setOrders] = useState([]); const [notifications, setNotifications] = useState([]); const [settings, setSettings] = useState({}); const [isEditing, setIsEditing] = useState(false); const [activeTab, setActiveTab] = useState('profile'); // 15 separate useEffects // 10 different event handlers // Multiple conditional renders // 300+ lines of chaos };
問題を見つけられますか?それらを詳しく見てみましょう。
修正
1) 高価な計算をメモ化する
レンダリングごとにすべてを再計算する代わりに、useMemo を使用して結果をキャッシュします。
// A cleaner, smarter approach const UserDashboard = () => { return ( <div> <UserProfile /> <OrderHistory /> <NotificationCenter /> <UserSettings /> </div> ); };
これにより、レンダリングのたびにデータの再計算やイベント ハンドラーの再作成が回避されます。また、メモを使用した子コンポーネントの不必要な再レンダリングも防ぎます。
2) 効率的な状態更新
状態管理が不十分だと、パフォーマンスが低下する可能性もあります。検索結果などの更新を処理するより良い方法は次のとおりです:
// This is exhausting const App = () => { const [user, setUser] = useState({}); return ( <Layout user={user}> <Sidebar user={user}> <Navigation user={user}> <UserMenu user={user} /> </Navigation> </Sidebar> </Layout> ); };
デバウンスにより、キーストロークごとにデータを取得することがなくなり、不必要な API 呼び出しや再レンダリングが削減されます。
パフォーマンスに関する簡単なヒント
- メモ化を多用しないでください。最適化する価値がある場合にのみ最適化してください。
- インライン関数を避ける: 安定した参照によりパフォーマンスが向上します。
- プロップを予測可能に保つ: 浅くて安定したプロップは、コンポーネントの効率を維持するのに役立ちます。
- 大きなリストを分割する:react-window のようなツールは、大きなデータセットを適切に処理できます。
- 状態を近づける: 実際に必要な状態のみを管理します。
- DevTools を使用したプロファイル: 最適化する前に必ず測定します。
結論
コンポーネントの構築はロケット科学ではありませんが、正直に言いましょう。悪い習慣につまずいてしまうのは簡単です。私はこれらすべての間違いを犯してきました(そして今でも時々犯します)。大丈夫です。重要なのは、それらを早期に発見し、修正し、粗雑なコードベースを避けることです。
より良いコンポーネントのためのクイックチェックリスト
✅ 単一の責任: コンポーネントのジョブを一文で要約できない場合は、コンポーネントを分解してください。
✅ 小道具の管理: 小道具をレイヤーの上にレイヤーを介して渡しますか?代わりにコンテキストを使用するか、合成を活用することを検討してください。
✅ 状態とエフェクト: エフェクトに焦点を当て、適切にクリーンアップし、最新のツールで複雑なデータの取得を処理させます。
✅ パフォーマンス: 目的のために最適化するのではなく、まず測定してください。必要に応じて、memo、useMemo、useCallback などのツールを賢く使用してください。
✅ シンプルに始める: いつか起こるかもしれない問題ではなく、今抱えている問題を解決してください。
最高のコンポーネントとは、派手でも賢すぎるものでもありません。チームが 6 か月後にうめき声を上げることなく読み、保守できるコンポーネントです。
覚えておいてください: これらは難しいルールではなく、単なるガイドラインです。時々壊れてしまうこともありますが、それはまったく問題ありません。目標は完璧ではありません。後でキャリアの選択を見直したときに、自分のキャリアの選択に疑問を抱かないようにするためのコンポーネントを構築することです。
以上がコンポーネントの間違いをやめてくださいの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。
