実のところ、コンポーネントは一見シンプルです。始めるのは簡単です。関数を定義し、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 };
聞き覚えがありますか?
次の場合、コンポーネントは「すべてのコンポーネント」になっている可能性があります。
解決策は?すべてを単一のコンポーネントにする代わりに、責任をより小さく集中した部分に分割します。
// 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 } ); };
簡単なヒント
これらの卑劣なパフォーマンスの問題について話しましょう。彼らは、すべてがうまくいっているように見えるため、実際はそうではないときまで、目立たないように行動するタイプです。これらの静かな犯人を明らかにし、それらを修正する方法を見てみましょう。
問題
ここでは、パフォーマンスに微妙な落とし穴があるコンポーネントを示します。
// 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 呼び出しや再レンダリングが削減されます。
パフォーマンスに関する簡単なヒント
コンポーネントの構築はロケット科学ではありませんが、正直に言いましょう。悪い習慣につまずいてしまうのは簡単です。私はこれらすべての間違いを犯してきました(そして今でも時々犯します)。大丈夫です。重要なのは、それらを早期に発見し、修正し、粗雑なコードベースを避けることです。
より良いコンポーネントのためのクイックチェックリスト
✅ 単一の責任: コンポーネントのジョブを一文で要約できない場合は、コンポーネントを分解してください。
✅ 小道具の管理: 小道具をレイヤーの上にレイヤーを介して渡しますか?代わりにコンテキストを使用するか、合成を活用することを検討してください。
✅ 状態とエフェクト: エフェクトに焦点を当て、適切にクリーンアップし、最新のツールで複雑なデータの取得を処理させます。
✅ パフォーマンス: 目的のために最適化するのではなく、まず測定してください。必要に応じて、memo、useMemo、useCallback などのツールを賢く使用してください。
✅ シンプルに始める: いつか起こるかもしれない問題ではなく、今抱えている問題を解決してください。
最高のコンポーネントとは、派手でも賢すぎるものでもありません。チームが 6 か月後にうめき声を上げることなく読み、保守できるコンポーネントです。
覚えておいてください: これらは難しいルールではなく、単なるガイドラインです。時々壊れてしまうこともありますが、それはまったく問題ありません。目標は完璧ではありません。後でキャリアの選択を見直したときに、自分のキャリアの選択に疑問を抱かないようにするためのコンポーネントを構築することです。
以上がコンポーネントの間違いをやめてくださいの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。