Reactのイベント処理|onClickの基本的な使い方

ReactのonClickイベント処理について基本的な使い方から応用例まで初心者向けに解説。イベントオブジェクト、引数の渡し方、実践的なコード例とともに詳しく説明します。

Learning Next 運営
34 分で読めます

あなたも、Reactのボタンを押しても何も起こらなくて困った経験はありませんか?

「onClickってどうやって使うの?」「ボタンクリックで関数を実行したい」「なんかエラーが出る...」

こんな悩みを持っている方、多いのではないでしょうか。

でも大丈夫です!

この記事では、ReactのonClickイベント処理について基本から応用まで丁寧に解説します。 初心者の方でも「あ、こういうことか!」と理解できるように、実際のコード例と一緒に学んでいきましょう。

onClickって何?基本的な使い方を覚えよう

ReactのonClickは、ユーザーがクリックしたときに何かを実行するためのイベントハンドラーです。

簡単に言うと、「ボタンを押したら、この処理をやってね」とReactに伝える方法なんです。

一番シンプルなonClickの例

まずは、一番基本的な例から見てみましょう。

import React from 'react';

function BasicButton() {
    // クリック時に実行される関数
    const handleClick = () => {
        alert('ボタンがクリックされました!');
    };

    return (
        <div>
            <h1>基本的なonClickの例</h1>
            <button onClick={handleClick}>
                クリックしてください
            </button>
        </div>
    );
}

export default BasicButton;

このコードを見てください。 handleClickという関数を作って、onClick={handleClick}でボタンに繋げています。

ボタンをクリックすると、アラートが表示されるんです。 シンプルですよね!

もっと簡単な書き方もあります

関数を別に作らずに、直接書くこともできます。

function InlineButton() {
    return (
        <div>
            <h1>インライン関数の例</h1>
            
            {/* 簡単な処理はこんな風に直接書けます */}
            <button onClick={() => alert('インライン関数です!')}>
                インラインボタン
            </button>
            
            {/* 複数行の処理も書けます */}
            <button onClick={() => {
                console.log('ボタンがクリックされました');
                alert('複数行の処理です');
            }}>
                複数行処理ボタン
            </button>
        </div>
    );
}

() => alert('...')のように、矢印関数で直接処理を書いています。 短い処理なら、この書き方も便利ですよ。

HTMLとの違いを知っておこう

HTMLとReactでは、書き方が少し違います。

<!-- HTML(従来の書き方) -->
<button onclick="handleClick()">クリック</button>

<!-- React(JSXの書き方) -->
<button onClick={handleClick}>クリック</button>

重要な違いはこちらです

  • HTMLではonclick(小文字)、ReactではonClick(キャメルケース)
  • HTMLでは文字列、Reactでは関数そのものを指定
  • HTMLでは()をつけますが、Reactでは関数名だけ

この違い、最初は混乱しがちですが慣れれば簡単です。

状態を変える実践的なonClick

onClickの真の力は、状態(state)を変更するときに発揮されます。

みんな大好き、カウンターアプリ

プログラミング学習の定番、カウンターアプリを作ってみましょう。

import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    // カウントを増加させる関数
    const increment = () => {
        setCount(count + 1);
    };

    // カウントを減少させる関数
    const decrement = () => {
        setCount(count - 1);
    };

    // カウントをリセットする関数
    const reset = () => {
        setCount(0);
    };

    return (
        <div style={{ textAlign: 'center', padding: '20px' }}>
            <h1>カウンター</h1>
            <h2 style={{ fontSize: '2rem', color: '#007bff' }}>
                {count}
            </h2>
            
            <div style={{ marginTop: '20px' }}>
                <button onClick={increment} style={{ margin: '0 5px' }}>
                    +1
                </button>
                <button onClick={decrement} style={{ margin: '0 5px' }}>
                    -1
                </button>
                <button onClick={reset} style={{ margin: '0 5px' }}>
                    リセット
                </button>
            </div>
        </div>
    );
}

このコードでは、useStateでカウントの状態を管理しています。

increment関数ではsetCount(count + 1)でカウントを1増やし、decrement関数では1減らしています。 reset関数では0に戻しています。

それぞれの関数をonClickでボタンに割り当てているんです。 ボタンを押すたびに画面の数字が変わるのが分かりますね。

表示・非表示の切り替え

次は、要素の表示・非表示を切り替える例を見てみましょう。

function ToggleVisibility() {
    const [isVisible, setIsVisible] = useState(true);

    const toggleVisibility = () => {
        setIsVisible(!isVisible);
    };

    return (
        <div style={{ padding: '20px' }}>
            <h1>表示切り替えの例</h1>
            
            <button onClick={toggleVisibility}>
                {isVisible ? '非表示にする' : '表示する'}
            </button>
            
            {isVisible && (
                <div style={{ 
                    marginTop: '20px', 
                    padding: '15px', 
                    backgroundColor: '#f0f8ff',
                    border: '1px solid #007bff',
                    borderRadius: '5px'
                }}>
                    <h3>この内容は表示・非表示を切り替えできます</h3>
                    <p>ボタンをクリックすると、この要素が消えたり現れたりします。</p>
                </div>
            )}
        </div>
    );
}

isVisibleという状態で表示・非表示を管理しています。 toggleVisibility関数では!isVisibleで状態を反転させています。

{isVisible && (...)} の部分で、isVisibleがtrueのときだけ要素を表示しているんです。 とても便利なパターンですよ。

テキストを動的に変える

もう少し複雑な例も見てみましょう。

function TextChanger() {
    const [message, setMessage] = useState('初期メッセージ');
    const [theme, setTheme] = useState('light');

    const messages = [
        'こんにちは!',
        'Reactは楽しいです',
        'onClickイベントを学習中',
        'プログラミングは面白い',
        '初期メッセージ'
    ];

    const changeMessage = () => {
        const randomIndex = Math.floor(Math.random() * messages.length);
        setMessage(messages[randomIndex]);
    };

    const toggleTheme = () => {
        setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
    };

    return (
        <div style={{
            padding: '20px',
            backgroundColor: theme === 'light' ? '#ffffff' : '#333333',
            color: theme === 'light' ? '#333333' : '#ffffff',
            minHeight: '200px',
            borderRadius: '8px'
        }}>
            <h1>テキスト変更の例</h1>
            <div style={{ fontSize: '1.5rem', margin: '20px 0' }}>
                {message}
            </div>
            
            <button onClick={changeMessage} style={{ margin: '0 10px' }}>
                メッセージ変更
            </button>
            <button onClick={toggleTheme} style={{ margin: '0 10px' }}>
                テーマ切り替え
            </button>
        </div>
    );
}

この例では、2つの状態を管理しています。

changeMessage関数では、配列からランダムにメッセージを選んで表示しています。 Math.random()で乱数を生成して、Math.floor()で整数にしているんです。

toggleTheme関数では、ライト・ダークテーマを切り替えています。 三項演算子(? :)を使って、現在のテーマに応じて新しいテーマを決めています。

イベントオブジェクトって何?活用方法を学ぼう

onClickイベントハンドラーには、イベントオブジェクトという便利な情報が自動的に渡されます。

「イベントオブジェクト」って聞くと難しそうですが、要するに「クリックに関する詳細情報」のことです。

イベントオブジェクトの基本

実際にどんな情報が取得できるか見てみましょう。

function EventObjectExample() {
    const handleClick = (event) => {
        console.log('イベントオブジェクト:', event);
        console.log('クリックされた要素:', event.target);
        console.log('イベントタイプ:', event.type);
        console.log('マウスのX座標:', event.clientX);
        console.log('マウスのY座標:', event.clientY);
        
        alert(`要素: ${event.target.tagName}, 座標: (${event.clientX}, ${event.clientY})`);
    };

    return (
        <div style={{ padding: '20px' }}>
            <h1>イベントオブジェクトの例</h1>
            <p>ボタンをクリックして、コンソールでイベント情報を確認してください。</p>
            
            <button onClick={handleClick} style={{ padding: '10px 20px' }}>
                イベント情報を表示
            </button>
        </div>
    );
}

handleClick関数の引数eventに、イベントオブジェクトが入っています。

event.targetでクリックされた要素、event.clientXevent.clientYでマウスの座標が取得できます。

ブラウザのコンソール(F12キーで開けます)を見ると、詳細な情報が確認できますよ。

クリック位置を追跡してみよう

もっと面白い例として、クリック位置を視覚化してみましょう。

function ClickPositionTracker() {
    const [clickPosition, setClickPosition] = useState({ x: 0, y: 0 });
    const [clickCount, setClickCount] = useState(0);

    const handleClick = (event) => {
        setClickPosition({
            x: event.clientX,
            y: event.clientY
        });
        setClickCount(prevCount => prevCount + 1);
    };

    return (
        <div style={{ padding: '20px' }}>
            <h1>クリック位置追跡</h1>
            <p>以下のエリアをクリックしてください:</p>
            
            <div
                onClick={handleClick}
                style={{
                    width: '400px',
                    height: '300px',
                    border: '2px solid #007bff',
                    backgroundColor: '#f0f8ff',
                    cursor: 'pointer',
                    position: 'relative',
                    margin: '20px 0'
                }}
            >
                クリックエリア
                {clickCount > 0 && (
                    <div
                        style={{
                            position: 'absolute',
                            left: clickPosition.x - 260,
                            top: clickPosition.y - 180,
                            width: '10px',
                            height: '10px',
                            backgroundColor: 'red',
                            borderRadius: '50%'
                        }}
                    />
                )}
            </div>
            
            <div>
                <p>クリック回数: {clickCount}</p>
                <p>最後のクリック位置: X: {clickPosition.x}, Y: {clickPosition.y}</p>
            </div>
        </div>
    );
}

このコードでは、クリックした位置に赤い丸を表示しています。

event.clientXevent.clientYでマウスの座標を取得して、状態として保存しています。 クリックするたびに、その位置に印がつくんです。

座標の調整(- 260- 180)は、要素の位置に合わせて表示位置を調整しているためです。

関数に引数を渡したい!その方法を覚えよう

「ボタンをクリックしたときに、特定の値を関数に渡したい」

これ、よくある要望ですよね。 でも、どうやってやるのでしょうか?

アロー関数で引数を渡す方法

一番よく使われる方法がこちらです。

function ParameterExample() {
    const [selectedUser, setSelectedUser] = useState(null);
    const [actionLog, setActionLog] = useState([]);

    const users = [
        { id: 1, name: '田中太郎', role: '管理者' },
        { id: 2, name: '佐藤花子', role: 'ユーザー' },
        { id: 3, name: '鈴木一郎', role: 'ゲスト' }
    ];

    // 引数を受け取る関数
    const selectUser = (userId, userName) => {
        const user = users.find(u => u.id === userId);
        setSelectedUser(user);
        
        const logEntry = `${new Date().toLocaleTimeString()}: ${userName} が選択されました`;
        setActionLog(prevLog => [...prevLog, logEntry]);
    };

    return (
        <div style={{ padding: '20px' }}>
            <h1>引数を渡すonClickの例</h1>
            
            <h3>ユーザー一覧</h3>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
                {users.map(user => (
                    <div key={user.id} style={{ 
                        border: '1px solid #ddd', 
                        padding: '10px', 
                        borderRadius: '5px' 
                    }}>
                        <p><strong>{user.name}</strong> ({user.role})</p>
                        <div>
                            {/* アロー関数で引数を渡す */}
                            <button 
                                onClick={() => selectUser(user.id, user.name)}
                                style={{ margin: '0 5px' }}
                            >
                                選択
                            </button>
                        </div>
                    </div>
                ))}
            </div>

            {selectedUser && (
                <div style={{ 
                    marginTop: '20px', 
                    padding: '15px', 
                    backgroundColor: '#e7f3ff',
                    borderRadius: '5px'
                }}>
                    <h3>選択されたユーザー</h3>
                    <p>名前: {selectedUser.name}</p>
                    <p>役割: {selectedUser.role}</p>
                </div>
            )}
        </div>
    );
}

ポイントはonClick={() => selectUser(user.id, user.name)}の部分です。

アロー関数() => ...で包むことで、クリック時に引数付きで関数を呼び出すことができるんです。

直接onClick={selectUser(user.id, user.name)}と書いてしまうと、ページが読み込まれた瞬間に関数が実行されてしまうので注意してください。

もっと複雑な引数の例

複数の引数や、より複雑な処理も可能です。

function AdvancedParameterExample() {
    const [cart, setCart] = useState([]);
    const [total, setTotal] = useState(0);

    const products = [
        { id: 1, name: 'ノートPC', price: 80000 },
        { id: 2, name: 'マウス', price: 2000 },
        { id: 3, name: 'キーボード', price: 5000 }
    ];

    // 商品をカートに追加する関数
    const addToCart = (product, quantity = 1) => {
        setCart(prevCart => {
            const existingItem = prevCart.find(item => item.id === product.id);
            if (existingItem) {
                return prevCart.map(item =>
                    item.id === product.id
                        ? { ...item, quantity: item.quantity + quantity }
                        : item
                );
            } else {
                return [...prevCart, { ...product, quantity }];
            }
        });
    };

    // 合計金額の計算
    React.useEffect(() => {
        const newTotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
        setTotal(newTotal);
    }, [cart]);

    return (
        <div style={{ padding: '20px' }}>
            <h1>ショッピングカートの例</h1>
            
            <div style={{ display: 'flex', gap: '20px' }}>
                <div style={{ flex: 1 }}>
                    <h3>商品一覧</h3>
                    {products.map(product => (
                        <div key={product.id} style={{ 
                            border: '1px solid #ddd', 
                            padding: '10px', 
                            margin: '10px 0',
                            borderRadius: '5px'
                        }}>
                            <h4>{product.name}</h4>
                            <p>価格: ¥{product.price.toLocaleString()}</p>
                            {/* 複数の引数を渡す例 */}
                            <button onClick={() => addToCart(product, 1)}>
                                カートに追加
                            </button>
                            <button onClick={() => addToCart(product, 3)}>
                                3個追加
                            </button>
                        </div>
                    ))}
                </div>

                <div style={{ flex: 1 }}>
                    <h3>ショッピングカート</h3>
                    {cart.length === 0 ? (
                        <p>カートは空です</p>
                    ) : (
                        <>
                            {cart.map(item => (
                                <div key={item.id} style={{ 
                                    border: '1px solid #ddd', 
                                    padding: '10px', 
                                    margin: '10px 0'
                                }}>
                                    <h4>{item.name}</h4>
                                    <p>数量: {item.quantity}</p>
                                    <p>小計: ¥{(item.price * item.quantity).toLocaleString()}</p>
                                </div>
                            ))}
                            <div style={{ fontWeight: 'bold', fontSize: '1.2rem' }}>
                                合計: ¥{total.toLocaleString()}
                            </div>
                        </>
                    )}
                </div>
            </div>
        </div>
    );
}

この例では、addToCart(product, 1)のように、商品オブジェクトと数量の2つの引数を渡しています。

「カートに追加」ボタンでは1個、「3個追加」ボタンでは3個を追加しています。 同じ関数でも、引数を変えることで違う動作をさせることができるんです。

実際の開発でよく使うパターン

理論も大切ですが、実際の開発でよく使われるパターンを知っておくとより実践的ですよね。

モーダルダイアログの制御

Webアプリでよく見る、ポップアップ画面(モーダル)の制御を作ってみましょう。

function ModalExample() {
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [modalContent, setModalContent] = useState('');

    const openModal = (content) => {
        setModalContent(content);
        setIsModalOpen(true);
    };

    const closeModal = () => {
        setIsModalOpen(false);
        setModalContent('');
    };

    const modalStyle = {
        position: 'fixed',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        backgroundColor: 'rgba(0, 0, 0, 0.5)',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        zIndex: 1000
    };

    return (
        <div style={{ padding: '20px' }}>
            <h1>モーダルダイアログの例</h1>
            
            <div>
                <button onClick={() => openModal('これは情報モーダルです。')}>
                    情報を表示
                </button>
                <button onClick={() => openModal('警告:この操作は取り消せません。')}>
                    警告を表示
                </button>
            </div>

            {isModalOpen && (
                <div style={modalStyle} onClick={closeModal}>
                    <div style={{
                        backgroundColor: 'white',
                        padding: '20px',
                        borderRadius: '8px',
                        maxWidth: '500px'
                    }} onClick={(e) => e.stopPropagation()}>
                        <h2>モーダル</h2>
                        <p>{modalContent}</p>
                        <button onClick={closeModal}>
                            閉じる
                        </button>
                    </div>
                </div>
            )}
        </div>
    );
}

このコードのポイントをいくつか説明しますね。

openModal関数では、表示するコンテンツを設定してモーダルを開いています。 closeModal関数では、モーダルを閉じてコンテンツをリセットしています。

onClick={(e) => e.stopPropagation()}の部分は、モーダルの中身をクリックしても閉じないようにする技術です。 e.stopPropagation()で、クリックイベントが親要素に伝わるのを防いでいるんです。

タブ切り替え機能

Webサイトでよく見るタブ機能も作ってみましょう。

function TabExample() {
    const [activeTab, setActiveTab] = useState('home');

    const tabs = [
        { id: 'home', label: 'ホーム', content: 'ホームページの内容です。' },
        { id: 'about', label: '会社概要', content: '私たちの会社について。' },
        { id: 'contact', label: 'お問い合わせ', content: 'お問い合わせ方法について。' }
    ];

    const handleTabClick = (tabId) => {
        setActiveTab(tabId);
    };

    const tabStyle = (isActive) => ({
        padding: '10px 20px',
        border: '1px solid #ddd',
        backgroundColor: isActive ? '#007bff' : '#f8f9fa',
        color: isActive ? 'white' : '#333',
        cursor: 'pointer'
    });

    const activeTabContent = tabs.find(tab => tab.id === activeTab);

    return (
        <div style={{ padding: '20px' }}>
            <h1>タブ切り替えの例</h1>
            
            <div style={{ display: 'flex' }}>
                {tabs.map(tab => (
                    <div
                        key={tab.id}
                        style={tabStyle(activeTab === tab.id)}
                        onClick={() => handleTabClick(tab.id)}
                    >
                        {tab.label}
                    </div>
                ))}
            </div>
            
            <div style={{ 
                padding: '20px', 
                border: '1px solid #ddd',
                minHeight: '200px'
            }}>
                <h2>{activeTabContent.label}</h2>
                <p>{activeTabContent.content}</p>
            </div>
        </div>
    );
}

activeTab状態で現在選択されているタブを管理しています。

handleTabClick関数で、クリックされたタブのIDをactiveTabにセットしています。 tabStyle関数では、アクティブなタブかどうかでスタイルを変えています。

tabs.find()でアクティブなタブのコンテンツを取得して表示しているんです。

よくある間違いと解決法

onClickを使っていると、よくある間違いがいくつかあります。 初心者の方が「あれ?動かない...」となりがちなポイントを見てみましょう。

1. 関数をすぐに呼び出してしまう間違い

これ、本当によくある間違いです。

// ❌ 間違った書き方
function BadExample() {
    const handleClick = () => {
        alert('クリックされました');
    };

    return (
        <div>
            {/* ページ読み込み時に即座に実行されてしまう */}
            <button onClick={handleClick()}>
                ボタン
            </button>
        </div>
    );
}

// ✅ 正しい書き方
function GoodExample() {
    const handleClick = () => {
        alert('クリックされました');
    };

    return (
        <div>
            {/* 関数の参照を渡す(()をつけない) */}
            <button onClick={handleClick}>
                ボタン
            </button>
            
            {/* またはアロー関数で包む */}
            <button onClick={() => handleClick()}>
                ボタン
            </button>
        </div>
    );
}

onClick={handleClick()}と書くと、ページが読み込まれた瞬間に関数が実行されてしまいます。 onClick={handleClick}のように、関数の参照を渡すのが正解です。

2. 状態更新のタイミングで混乱

Reactの状態更新は、少し特殊な動きをします。

// ❌ 期待通りに動かない例
function BadStateUpdate() {
    const [count, setCount] = useState(0);

    const handleMultipleClicks = () => {
        // 同じ値での複数回更新(期待通りに動かない)
        setCount(count + 1);
        setCount(count + 1);
        setCount(count + 1);
        // 結果:1しか増えない
    };

    return (
        <div>
            <p>カウント: {count}</p>
            <button onClick={handleMultipleClicks}>
                3回増加(期待通りに動かない)
            </button>
        </div>
    );
}

// ✅ 正しい方法
function GoodStateUpdate() {
    const [count, setCount] = useState(0);

    const handleMultipleClicks = () => {
        // 前の状態に基づいて更新
        setCount(prevCount => prevCount + 1);
        setCount(prevCount => prevCount + 1);
        setCount(prevCount => prevCount + 1);
        // 結果:3増える
    };

    return (
        <div>
            <p>カウント: {count}</p>
            <button onClick={handleMultipleClicks}>
                3回増加(正しく動く)
            </button>
        </div>
    );
}

setCount(count + 1)を複数回書いても、countの値は同じなので1しか増えません。

setCount(prevCount => prevCount + 1)のように、前の値を引数で受け取る書き方をすると、正しく動作します。

3. HTMLとReactの書き方を混同

HTMLでの書き方をReactでやってしまう間違いもよくあります。

// ❌ HTMLの書き方をReactでやってしまう
function BadHTMLStyle() {
    return (
        <div>
            {/* 文字列で書いてしまう(動かない) */}
            <button onclick="alert('Hello')">
                ボタン1
            </button>
            
            {/* onclickが小文字(動かない) */}
            <button onclick={() => alert('Hello')}>
                ボタン2
            </button>
        </div>
    );
}

// ✅ Reactの正しい書き方
function GoodReactStyle() {
    return (
        <div>
            {/* onClickはキャメルケース、関数を直接指定 */}
            <button onClick={() => alert('Hello')}>
                ボタン
            </button>
        </div>
    );
}

ReactではonClick(キャメルケース)を使い、文字列ではなく関数を指定します。 HTMLの書き方に慣れていると、ついつい間違えてしまいがちですね。

まとめ:onClickをマスターしよう

お疲れ様でした! ReactのonClickイベント処理について、基本から応用まで一緒に学んできました。

重要なポイントをもう一度整理しておきますね

  • 基本: onClick={関数名}で関数の参照を渡す
  • 引数: アロー関数で包んでonClick={() => 関数(引数)}
  • 状態更新: 前の値を使う場合はsetState(prev => prev + 1)
  • イベントオブジェクト: クリック情報(座標、要素など)が自動で渡される
  • よくある間違い: onClick={関数()}は即座に実行されてしまう

onClickは、Reactでユーザーとのインタラクションを作る基本中の基本です。 最初は戸惑うかもしれませんが、何度も練習すれば必ず身につきます。

今回学んだパターンを参考に、ぜひ自分でもいろんなボタンやインタラクションを作ってみてくださいね。

実際に手を動かして作ることで、「あ、こういうことか!」という理解が深まりますよ。

頑張ってください!

関連記事