Reactのデフォルト値設定|defaultPropsとデフォルト引数

Reactコンポーネントでのデフォルト値設定を詳しく解説。defaultProps、デフォルト引数、分割代入の使い方と比較を実例付きで説明します。

Learning Next 運営
30 分で読めます

みなさん、Reactコンポーネントでpropsのデフォルト値を設定したいと思ったことはありませんか?

「propsが渡されなかった時に初期値を設定したい」と考えたことがある方も多いでしょう。 「defaultPropsの使い方がわからない」「デフォルト引数との違いは何?」という疑問を抱いている方もいるかもしれません。

実は、Reactでは複数の方法でデフォルト値を設定できます。 それぞれに特徴があり、使い分けることでより良いコンポーネントが作れるんです。

この記事では、Reactでのデフォルト値設定について、defaultPropsとデフォルト引数の使い方を詳しく解説します。 それぞれの特徴や使い分け方法を、実際のコード例とともに学んでいきましょう。

デフォルト値設定の基本を理解しよう

まず、なぜデフォルト値の設定が重要なのかを理解しましょう。

デフォルト値が必要な理由

Reactコンポーネントでは、propsが渡されない場合があります。

// propsが渡されない場合
function App() {
    return (
        <div>
            <Button />  {/* textプロパティが渡されていない */}
        </div>
    );
}

function Button({ text }) {
    return <button>{text}</button>; // undefinedが表示される
}

このような場合、適切なデフォルト値を設定することで、エラーを防ぎ、使いやすいコンポーネントを作成できます。

デフォルト値設定の方法

Reactでは、主に以下の3つの方法でデフォルト値を設定できます。

1. defaultProps(クラスコンポーネント・関数コンポーネント両対応)

2. デフォルト引数(関数コンポーネントのみ)

3. 分割代入でのデフォルト値(関数コンポーネントのみ)

それぞれの使い方を詳しく見ていきましょう。

defaultPropsの使い方をマスターしよう

defaultPropsは、Reactの従来的なデフォルト値設定方法です。

関数コンポーネントでのdefaultProps

function Button({ text, color, size }) {
    return (
        <button 
            style={{ 
                color: color,
                fontSize: size === 'large' ? '18px' : '14px'
            }}
        >
            {text}
        </button>
    );
}

// defaultPropsを設定
Button.defaultProps = {
    text: 'クリック',
    color: 'blue',
    size: 'medium'
};

このコードでは、Buttonコンポーネントに3つのデフォルト値を設定しています。

実際に使ってみると、こんな風になります。

function App() {
    return (
        <div>
            <Button />  {/* 全てデフォルト値 */}
            <Button text="送信" />  {/* textのみ指定 */}
            <Button text="削除" color="red" size="large" />
        </div>
    );
}

とても便利ですね!

クラスコンポーネントでのdefaultProps

クラスコンポーネントでも使えます。

class UserCard extends React.Component {
    render() {
        const { name, role, department, avatar } = this.props;
        
        return (
            <div className="user-card">
                <img src={avatar} alt={name} />
                <h3>{name}</h3>
                <p>役職: {role}</p>
                <p>部署: {department}</p>
            </div>
        );
    }
}

// クラスコンポーネントでのdefaultProps設定
UserCard.defaultProps = {
    role: '一般社員',
    department: '未所属',
    avatar: '/default-avatar.png'
};

クラス内で定義することもできます。

class UserCardWithStaticProps extends React.Component {
    static defaultProps = {
        role: '一般社員',
        department: '未所属',
        avatar: '/default-avatar.png'
    };
    
    render() {
        const { name, role, department, avatar } = this.props;
        
        return (
            <div className="user-card">
                <img src={avatar} alt={name} />
                <h3>{name}</h3>
                <p>役職: {role}</p>
                <p>部署: {department}</p>
            </div>
        );
    }
}

static defaultPropsを使うと、クラス内で定義できて便利です。

複雑なデフォルト値の設定

関数やオブジェクトもデフォルト値として設定できます。

function ProductCard({ product, showPrice, currency, onAddToCart }) {
    const handleAddToCart = () => {
        if (onAddToCart) {
            onAddToCart(product);
        }
    };
    
    return (
        <div className="product-card">
            <h3>{product.name}</h3>
            <p>{product.description}</p>
            {showPrice && (
                <p className="price">
                    {currency}{product.price}
                </p>
            )}
            <button onClick={handleAddToCart}>
                カートに追加
            </button>
        </div>
    );
}

ProductCard.defaultProps = {
    showPrice: true,
    currency: '¥',
    onAddToCart: () => {
        console.log('デフォルトのカート追加処理');
    }
};

関数をデフォルト値に設定することで、呼び出し元で処理を定義しなくても安全に動作します。

デフォルト引数の使い方を覚えよう

ES6のデフォルト引数を使用する方法です。 モダンなReact開発では、この方法がよく使われます。

基本的な使い方

// デフォルト引数を使用
function Greeting({ name = '匿名', timeOfDay = '日中' }) {
    return (
        <div>
            <h2>こんにちは、{name}さん!</h2>
            <p>{timeOfDay}の時間帯ですね。</p>
        </div>
    );
}

// 使用例
function App() {
    return (
        <div>
            <Greeting />  {/* 全てデフォルト値 */}
            <Greeting name="田中" />  {/* nameのみ指定 */}
            <Greeting name="佐藤" timeOfDay="朝" />
        </div>
    );
}

この方法は、とてもシンプルで読みやすいのが特徴です。

複雑なデフォルト値

オブジェクトや配列もデフォルト値として設定できます。

function ConfigPanel({ 
    theme = 'light',
    language = 'ja',
    notifications = { email: true, push: false },
    layout = { sidebar: true, toolbar: true }
}) {
    return (
        <div className={`config-panel theme-${theme}`}>
            <h3>設定パネル</h3>
            <div>
                <label>テーマ: {theme}</label>
                <label>言語: {language}</label>
            </div>
            <div>
                <label>
                    メール通知: {notifications.email ? 'ON' : 'OFF'}
                </label>
                <label>
                    プッシュ通知: {notifications.push ? 'ON' : 'OFF'}
                </label>
            </div>
            <div>
                <label>
                    サイドバー: {layout.sidebar ? '表示' : '非表示'}
                </label>
                <label>
                    ツールバー: {layout.toolbar ? '表示' : '非表示'}
                </label>
            </div>
        </div>
    );
}

この例では、オブジェクトをデフォルト値として設定しています。

関数をデフォルト値にする

関数もデフォルト値として設定できます。

function SearchBox({ 
    placeholder = '検索キーワードを入力',
    onSearch = (query) => console.log('検索:', query),
    onClear = () => console.log('クリア'),
    debounceTime = 300
}) {
    const [query, setQuery] = useState('');
    
    // デバウンス処理
    useEffect(() => {
        const timer = setTimeout(() => {
            if (query) {
                onSearch(query);
            }
        }, debounceTime);
        
        return () => clearTimeout(timer);
    }, [query, onSearch, debounceTime]);
    
    const handleClear = () => {
        setQuery('');
        onClear();
    };
    
    return (
        <div className="search-box">
            <input 
                type="text"
                placeholder={placeholder}
                value={query}
                onChange={(e) => setQuery(e.target.value)}
            />
            <button onClick={handleClear}>クリア</button>
        </div>
    );
}

関数をデフォルト値に設定することで、コンポーネントが安全に動作します。

分割代入でのデフォルト値を試してみよう

分割代入と同時にデフォルト値を設定する方法です。 より柔軟な設定が可能になります。

基本的な分割代入

function UserProfile(props) {
    // 分割代入でデフォルト値を設定
    const {
        name = '名前未設定',
        age = 0,
        email = 'メールアドレス未設定',
        avatar = '/default-avatar.png',
        isActive = false
    } = props;
    
    return (
        <div className="user-profile">
            <img src={avatar} alt={name} />
            <h2>{name}</h2>
            <p>年齢: {age}歳</p>
            <p>メール: {email}</p>
            <span className={`status ${isActive ? 'active' : 'inactive'}`}>
                {isActive ? 'アクティブ' : '非アクティブ'}
            </span>
        </div>
    );
}

この方法は、コンポーネント内で柔軟にデフォルト値を設定できます。

ネストしたオブジェクトの分割代入

複雑なオブジェクト構造にも対応できます。

function AddressCard(props) {
    // ネストしたオブジェクトの分割代入
    const {
        address: {
            street = '住所未設定',
            city = '市区町村未設定',
            zipCode = '郵便番号未設定'
        } = {},
        contact: {
            phone = '電話番号未設定',
            fax = 'FAX番号未設定'
        } = {}
    } = props;
    
    return (
        <div className="address-card">
            <h3>住所情報</h3>
            <p>郵便番号: {zipCode}</p>
            <p>住所: {city} {street}</p>
            <h3>連絡先</h3>
            <p>電話: {phone}</p>
            <p>FAX: {fax}</p>
        </div>
    );
}

この例では、ネストしたオブジェクトのデフォルト値を設定しています。

使用例を見てみましょう。

function App() {
    return (
        <div>
            <AddressCard />  {/* 全てデフォルト値 */}
            <AddressCard 
                address={{ street: '1-2-3', city: '東京都新宿区' }}
                contact={{ phone: '03-1234-5678' }}
            />
        </div>
    );
}

とても柔軟に使えますね!

配列の分割代入

配列も分割代入できます。

function ColorPalette(props) {
    // 配列の分割代入でデフォルト値
    const {
        colors = ['#FF0000', '#00FF00', '#0000FF'],
        title = 'カラーパレット'
    } = props;
    
    // 配列をさらに分割代入
    const [primary, secondary, accent] = colors;
    
    return (
        <div className="color-palette">
            <h3>{title}</h3>
            <div className="colors">
                <div 
                    style={{ backgroundColor: primary }}
                    className="color-box"
                >
                    Primary
                </div>
                <div 
                    style={{ backgroundColor: secondary }}
                    className="color-box"
                >
                    Secondary
                </div>
                <div 
                    style={{ backgroundColor: accent }}
                    className="color-box"
                >
                    Accent
                </div>
            </div>
        </div>
    );
}

配列の分割代入も便利に使えます。

各方法の比較と使い分けを知ろう

それぞれの方法の特徴と使い分けを比較しましょう。

パフォーマンスの比較

// 1. defaultProps(少し重い)
function ComponentA({ title, count }) {
    return <div>{title}: {count}</div>;
}
ComponentA.defaultProps = {
    title: 'デフォルトタイトル',
    count: 0
};

// 2. デフォルト引数(軽い)
function ComponentB({ title = 'デフォルトタイトル', count = 0 }) {
    return <div>{title}: {count}</div>;
}

// 3. 分割代入(軽い)
function ComponentC(props) {
    const { title = 'デフォルトタイトル', count = 0 } = props;
    return <div>{title}: {count}</div>;
}

デフォルト引数と分割代入の方が軽量です。

TypeScriptでの型安全性

TypeScriptを使う場合は、以下のような書き方になります。

// TypeScriptでの型定義
interface ButtonProps {
    text?: string;
    variant?: 'primary' | 'secondary' | 'danger';
    size?: 'small' | 'medium' | 'large';
    disabled?: boolean;
}

// デフォルト引数(TypeScript推奨)
function Button({ 
    text = 'ボタン',
    variant = 'primary',
    size = 'medium',
    disabled = false 
}: ButtonProps) {
    return (
        <button 
            className={`btn btn-${variant} btn-${size}`}
            disabled={disabled}
        >
            {text}
        </button>
    );
}

TypeScriptでは、デフォルト引数が型安全性で有利です。

使い分けの指針

// 使い分けの基準

// 1. 新しいプロジェクト → デフォルト引数を推奨
function ModernComponent({ name = 'デフォルト', age = 0 }) {
    return <div>{name} ({age}歳)</div>;
}

// 2. レガシーコード・クラスコンポーネント → defaultProps
class LegacyComponent extends React.Component {
    static defaultProps = {
        name: 'デフォルト',
        age: 0
    };
    
    render() {
        const { name, age } = this.props;
        return <div>{name} ({age}歳)</div>;
    }
}

// 3. 複雑な条件分岐 → 分割代入
function ComplexComponent(props) {
    const {
        user = {},
        settings = {},
        theme = 'light'
    } = props;
    
    const {
        name = '未設定',
        email = '未設定'
    } = user;
    
    return <div>...</div>;
}

プロジェクトの性質に応じて使い分けしましょう。

実践的な使用例で学ぼう

より実践的な使用例を紹介します。

Modalコンポーネントでのデフォルト値

function Modal({ 
    isOpen = false,
    title = 'モーダル',
    children,
    onClose = () => {},
    size = 'medium',
    showCloseButton = true,
    overlay = true,
    animation = 'fade'
}) {
    if (!isOpen) return null;
    
    const modalClasses = `modal modal-${size} animation-${animation}`;
    
    return (
        <div className="modal-wrapper">
            {overlay && <div className="modal-overlay" onClick={onClose} />}
            <div className={modalClasses}>
                <div className="modal-header">
                    <h2>{title}</h2>
                    {showCloseButton && (
                        <button onClick={onClose} className="close-button">
                            ×
                        </button>
                    )}
                </div>
                <div className="modal-content">
                    {children}
                </div>
            </div>
        </div>
    );
}

このModalコンポーネントは、多くのデフォルト値を設定することで、シンプルに使えるようになっています。

使用例を見てみましょう。

function App() {
    const [isModalOpen, setIsModalOpen] = useState(false);
    
    return (
        <div>
            <button onClick={() => setIsModalOpen(true)}>
                モーダルを開く
            </button>
            
            <Modal 
                isOpen={isModalOpen}
                onClose={() => setIsModalOpen(false)}
                title="設定"
                size="large"
            >
                <p>モーダルの内容</p>
            </Modal>
        </div>
    );
}

必要な部分だけを指定すれば良いので、とても使いやすいです。

フォームコンポーネントでのデフォルト値

function FormField({ 
    label,
    type = 'text',
    name,
    value,
    onChange,
    placeholder = '',
    required = false,
    disabled = false,
    error = '',
    helpText = '',
    validation = {}
}) {
    const fieldId = `field-${name}`;
    const hasError = error.length > 0;
    
    return (
        <div className={`form-field ${hasError ? 'has-error' : ''}`}>
            <label htmlFor={fieldId} className="field-label">
                {label}
                {required && <span className="required">*</span>}
            </label>
            
            <input 
                id={fieldId}
                type={type}
                name={name}
                value={value}
                onChange={onChange}
                placeholder={placeholder}
                required={required}
                disabled={disabled}
                className="field-input"
                {...validation}
            />
            
            {helpText && (
                <div className="help-text">{helpText}</div>
            )}
            
            {hasError && (
                <div className="error-message">{error}</div>
            )}
        </div>
    );
}

フォームフィールドでは、多くのオプションにデフォルト値を設定することで、使いやすさを向上させています。

カスタムフックでのデフォルト値

function useLocalStorage(key, initialValue = null) {
    const [storedValue, setStoredValue] = useState(() => {
        try {
            const item = window.localStorage.getItem(key);
            return item ? JSON.parse(item) : initialValue;
        } catch (error) {
            console.error('localStorage error:', error);
            return initialValue;
        }
    });
    
    const setValue = (value) => {
        try {
            setStoredValue(value);
            window.localStorage.setItem(key, JSON.stringify(value));
        } catch (error) {
            console.error('localStorage error:', error);
        }
    };
    
    return [storedValue, setValue];
}

カスタムフックでも、デフォルト値を設定することで安全に使えます。

使用例を見てみましょう。

function UserPreferences() {
    const [theme, setTheme] = useLocalStorage('theme', 'light');
    const [language, setLanguage] = useLocalStorage('language', 'ja');
    const [notifications, setNotifications] = useLocalStorage('notifications', {
        email: true,
        push: false
    });
    
    return (
        <div>
            <h3>ユーザー設定</h3>
            <p>テーマ: {theme}</p>
            <p>言語: {language}</p>
            <p>通知設定: {JSON.stringify(notifications)}</p>
        </div>
    );
}

デフォルト値を設定することで、初回アクセス時も安全に動作します。

ベストプラクティスを実践しよう

デフォルト値設定のベストプラクティスを紹介します。

1. 一貫性のある命名

// 良い例:一貫性のある命名
function Button({ 
    text = 'ボタン',
    variant = 'primary',
    size = 'medium',
    disabled = false,
    loading = false
}) {
    return (
        <button 
            className={`btn btn-${variant} btn-${size}`}
            disabled={disabled || loading}
        >
            {loading ? 'Loading...' : text}
        </button>
    );
}

// 悪い例:一貫性のない命名
function BadButton({ 
    txt = 'ボタン',        // textと略語の混在
    type = 'primary',       // variantと意味が不明確
    buttonSize = 'medium',  // sizeと冗長
    isDisabled = false      // disabledとis接頭辞の混在
}) {
    // ...
}

一貫性のある命名により、使いやすさが向上します。

2. 適切なデフォルト値の選択

// 良い例:直感的なデフォルト値
function Pagination({ 
    currentPage = 1,        // 1から始まる
    totalPages = 1,         // 最小値
    pageSize = 10,          // 一般的な値
    showPageInfo = true,    // 便利な機能はデフォルトで有効
    showFirstLast = false   // 高度な機能はデフォルトで無効
}) {
    // ...
}

// 悪い例:直感的でないデフォルト値
function BadPagination({ 
    currentPage = 0,        // 0から始まるのは直感的でない
    totalPages = 0,         // 無効な状態
    pageSize = 1,           // 実用的でない値
    showPageInfo = false    // 基本的な情報が非表示
}) {
    // ...
}

直感的なデフォルト値を選ぶことで、使いやすさが向上します。

3. パフォーマンスを考慮したデフォルト値

// 良い例:パフォーマンスを考慮
const DEFAULT_OPTIONS = {
    theme: 'light',
    animations: true,
    caching: true
};

function AppComponent({ options = DEFAULT_OPTIONS }) {
    // 毎回新しいオブジェクトを作成しない
    return <div>...</div>;
}

// 悪い例:毎回新しいオブジェクト
function BadAppComponent({ 
    options = { theme: 'light', animations: true, caching: true }
}) {
    // 毎回新しいオブジェクトが作成される
    return <div>...</div>;
}

パフォーマンスを考慮したデフォルト値の設定が重要です。

まとめ:適切なデフォルト値設定を選択しよう

Reactでのデフォルト値設定について、詳しく解説しました。

3つの主要な方法

  1. defaultProps - レガシーコードやクラスコンポーネントに適している
  2. デフォルト引数 - モダンな関数コンポーネントに最適
  3. 分割代入 - 複雑な条件や柔軟性が必要な場合に有効

選択の指針

  • 新しいプロジェクト: デフォルト引数を推奨
  • TypeScript: デフォルト引数が型安全性で有利
  • 複雑な条件: 分割代入が柔軟で対応しやすい
  • レガシーコード: defaultPropsで一貫性を保つ

ベストプラクティス

  • 一貫性のある命名規則
  • 直感的なデフォルト値の選択
  • パフォーマンスを考慮した実装
  • 適切なドキュメント化

重要なポイント

  • プロジェクトの要件に合わせて選択する
  • チーム内で統一した方法を使用する
  • 可読性と保守性を重視する
  • パフォーマンスへの影響を考慮する

デフォルト値の設定は、使いやすく堅牢なコンポーネントを作るための重要な要素です。 適切な方法を選択して、より良いReactアプリケーションを開発していきましょう!

関連記事