12月 21, 2025
49 分で読める

React Native シニア面接質問と回答

interview
career-advice
job-search
React Native シニア面接質問と回答
Milad Bonakdar

Milad Bonakdar

著者

シニアReact Native面接に向けて、アーキテクチャ、FlatList性能、ネイティブモジュール、状態管理、テスト、本番運用の判断を整理します。


はじめに

シニアReact Native面接では、構文だけを問われることはほとんどありません。アプリ設計、パフォーマンス計測、ネイティブ連携、状態とデータの境界、テスト戦略、リリース品質、実際のプロダクト制約の中でどうトレードオフを説明するかが見られます。

このガイドでは、シニアらしい簡潔な回答を練習できます。まず自分ならどう判断するかを述べ、その理由、リスク、代替策を説明しましょう。たとえばFlatListなら「最適化できます」で終わらせず、空白領域、レンダリングバッチ、メモ化した行、安定したkey、固定高さや重い画像が原因のときの設計変更まで説明します。


高度なReactとHooks (5つの質問)

1. useMemouseCallbackについて説明してください。いつ使用すべきですか?

回答: これらのHooksはどちらも、値や関数をメモ化することでパフォーマンスを最適化します。

  • useMemo: 計算された値(コストのかかる計算)をメモ化します。
  • useCallback: 関数参照をメモ化します(再作成を防ぎます)。
  • いつ使用すべきか: パフォーマンスの問題が発生した場合のみ。時期尚早な最適化は、コードを読みにくくする可能性があります。
import { useMemo, useCallback, useState } from 'react';

function ExpensiveComponent({ items, onItemClick }) {
  // useMemo - コストのかかる計算をメモ化
  const sortedItems = useMemo(() => {
    console.log('Sorting items...');
    return items.sort((a, b) => a.price - b.price);
  }, [items]); // itemsが変更された場合にのみ再計算
  
  // useCallback - 関数をメモ化
  const handleClick = useCallback((id) => {
    console.log('Item clicked:', id);
    onItemClick(id);
  }, [onItemClick]); // onItemClickが変更された場合にのみ再作成
  
  return (
    <FlatList
      data={sortedItems}
      renderItem={({ item }) => (
        <ItemRow item={item} onClick={handleClick} />
      )}
    />
  );
}

// React.memoを使用した子コンポーネント
const ItemRow = React.memo(({ item, onClick }) => {
  console.log('Rendering item:', item.id);
  return (
    <TouchableOpacity onPress={() => onClick(item.id)}>
      <Text>{item.name}</Text>
    </TouchableOpacity>
  );
});

希少性: 非常に一般的 難易度:


2. useRefとは何ですか?また、そのユースケースは何ですか?

回答: useRefは、再レンダリングを引き起こすことなく、レンダリング間で永続化される可変の参照を作成します。

  • ユースケース:
    • DOM/ネイティブ要素へのアクセス
    • 再レンダリングをトリガーせずに可変の値を格納
    • 以前の値を保持
    • タイマー/インターバルの格納
import { useRef, useEffect } from 'react';
import { TextInput, Animated } from 'react-native';

function FormComponent() {
  const inputRef = useRef(null);
  const previousValue = useRef('');
  const animatedValue = useRef(new Animated.Value(0)).current;
  
  useEffect(() => {
    // マウント時に入力をフォーカス
    inputRef.current?.focus();
  }, []);
  
  const handleChange = (text) => {
    console.log('Previous:', previousValue.current);
    console.log('Current:', text);
    previousValue.current = text;
  };
  
  const startAnimation = () => {
    Animated.timing(animatedValue, {
      toValue: 1,
      duration: 300,
      useNativeDriver: true,
    }).start();
  };
  
  return (
    <View>
      <TextInput ref={inputRef} onChangeText={handleChange} />
      <Animated.View style={{ opacity: animatedValue }}>
        <Text>Animated Content</Text>
      </Animated.View>
    </View>
  );
}

// タイマーの例
function Timer() {
  const intervalRef = useRef(null);
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(intervalRef.current);
  }, []);
  
  return <Text>{count}</Text>;
}

希少性: 一般的 難易度:


3. カスタムHooksについて説明し、いつ作成すべきかを説明してください。

回答: カスタムHooksは、再利用可能な状態を持つロジックを個別の関数に抽出します。

  • 利点: コードの再利用、関心の分離、簡単なテスト
  • 規則: "use"で始まる必要があります。
// APIフェッチ用のカスタムhook
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
  }, [url]);
  
  return { data, loading, error };
}

// フォーム処理用のカスタムhook
function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  
  const handleChange = (name, value) => {
    setValues(prev => ({ ...prev, [name]: value }));
  };
  
  const validate = (validationRules) => {
    const newErrors = {};
    Object.keys(validationRules).forEach(field => {
      const rule = validationRules[field];
      if (rule.required && !values[field]) {
        newErrors[field] = `${field} is required`;
      }
    });
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };
  
  return { values, errors, handleChange, validate };
}

// 使用例
function UserProfile() {
  const { data, loading, error } = useFetch('https://api.example.com/user');
  const { values, errors, handleChange, validate } = useForm({
    name: '',
    email: '',
  });
  
  if (loading) return <ActivityIndicator />;
  if (error) return <Text>Error: {error}</Text>;
  
  return <Text>{data.name}</Text>;
}

希少性: 一般的 難易度:


4. React Contextとは何ですか?また、いつ使用すべきですか?

回答: Contextは、propsを掘り下げることなく、コンポーネントツリー全体にデータを渡す方法を提供します。

  • ユースケース: テーマ、認証、言語設定
  • 注意: 注意して使用しないと、不要な再レンダリングが発生する可能性があります。
import { createContext, useContext, useState } from 'react';

// Contextを作成
const ThemeContext = createContext();
const AuthContext = createContext();

// テーマプロバイダー
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 認証プロバイダー
function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  
  const login = async (credentials) => {
    const user = await loginAPI(credentials);
    setUser(user);
  };
  
  const logout = () => {
    setUser(null);
  };
  
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Context用のカスタムhook
function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

function useAuth() {
  return useContext(AuthContext);
}

// 使用例
function App() {
  return (
    <ThemeProvider>
      <AuthProvider>
        <MainApp />
      </AuthProvider>
    </ThemeProvider>
  );
}

function ThemedButton() {
  const { theme, toggleTheme } = useTheme();
  const { user } = useAuth();
  
  return (
    <TouchableOpacity
      style={{ backgroundColor: theme === 'light' ? '#fff' : '#333' }}
      onPress={toggleTheme}
    >
      <Text>{user ? `Hello, ${user.name}` : 'Guest'}</Text>
    </TouchableOpacity>
  );
}

希少性: 非常に一般的 難易度:


5. useEffectuseLayoutEffectの違いについて説明してください。

回答: どちらも副作用を実行しますが、タイミングが異なります。

  • useEffect: レンダリングが画面に描画された後、非同期で実行されます。
  • useLayoutEffect: 描画前に同期的に実行されます(視覚的な更新をブロックします)。
  • useLayoutEffectを使用する場合: DOMを測定する必要がある場合、または視覚的なちらつきを防ぐ必要がある場合。
import { useEffect, useLayoutEffect, useRef, useState } from 'react';

function MeasureComponent() {
  const [height, setHeight] = useState(0);
  const elementRef = useRef(null);
  
  // useLayoutEffect - 描画前に測定
  useLayoutEffect(() => {
    if (elementRef.current) {
      const { height } = elementRef.current.measure((x, y, width, height) => {
        setHeight(height);
      });
    }
  }, []);
  
  // useEffect - 描画後
  useEffect(() => {
    console.log('Component rendered');
  }, []);
  
  return (
    <View ref={elementRef}>
      <Text>Height: {height}</Text>
    </View>
  );
}

希少性:難易度: 難しい


状態管理 (4つの質問)

6. Reduxとそのコア原則について説明してください。

回答: Reduxは、JavaScriptアプリケーションのための予測可能な状態コンテナです。

Loading diagram...
  • コア原則:
    • 単一の信頼できる情報源(1つのストア)
    • 状態は読み取り専用(変更するにはアクションをディスパッチ)
    • 純粋関数(リデューサー)で変更
// アクションタイプ
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';

// アクションクリエイター
const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { id: Date.now(), text, completed: false },
});

const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  payload: id,
});

// リデューサー
const todosReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, action.payload];
    case TOGGLE_TODO:
      return state.map(todo =>
        todo.id === action.payload
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
};

// ストア
import { createStore } from 'redux';
const store = createStore(todosReducer);

// React Nativeコンポーネント
import { useSelector, useDispatch } from 'react-redux';

function TodoList() {
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();
  
  return (
    <View>
      <FlatList
        data={todos}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => dispatch(toggleTodo(item.id))}>
            <Text style={{ textDecorationLine: item.completed ? 'line-through' : 'none' }}>
              {item.text}
            </Text>
          </TouchableOpacity>
        )}
      />
      <Button title="Add" onPress={() => dispatch(addTodo('New Task'))} />
    </View>
  );
}

希少性: 非常に一般的 難易度: 難しい


7. Redux Toolkitとは何ですか?また、どのようにReduxを簡素化しますか?

回答: Redux Toolkitは、Reduxロジックを記述するための公式推奨方法です。

  • 利点:
    • ボイラープレートの削減
    • 不変アップデートのためのImmerが組み込まれています
    • Redux Thunkが含まれています
    • TypeScriptのサポートが向上
import { createSlice, configureStore } from '@reduxjs/toolkit';

// スライス(アクションとリデューサーを組み合わせる)
const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      // Immerは「ミューテーション」コードを許可します
      state.push({
        id: Date.now(),
        text: action.payload,
        completed: false,
      });
    },
    toggleTodo: (state, action) => {
      const todo = state.find(t => t.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
  },
});

export const { addTodo, toggleTodo } = todosSlice.actions;

// ストア
const store = configureStore({
  reducer: {
    todos: todosSlice.reducer,
  },
});

// 非同期サンク
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchTodos = createAsyncThunk(
  'todos/fetchTodos',
  async () => {
    const response = await fetch('https://api.example.com/todos');
    return response.json();
  }
);

const todosSlice = createSlice({
  name: 'todos',
  initialState: { items: [], loading: false, error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchTodos.pending, (state) => {
        state.loading = true;
      })
      .addCase(fetchTodos.fulfilled, (state, action) => {
        state.loading = false;
        state.items = action.payload;
      })
      .addCase(fetchTodos.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

希少性: 一般的 難易度:


8. 状態管理のためのReduxの代替手段は何ですか?

回答: 複数の状態管理ソリューションが存在します。

  • Context API + useReducer: 組み込み、シンプルなアプリケーションに適しています
  • MobX: Observableベース、ボイラープレートの削減
  • Zustand: 最小限、フックベース
  • Recoil: Facebookによる、アトムベース
  • Jotai: プリミティブアトム
// Zustandの例
import create from 'zustand';

const useStore = create((set) => ({
  todos: [],
  addTodo: (text) => set((state) => ({
    todos: [...state.todos, { id: Date.now(), text, completed: false }],
  })),
  toggleTodo: (id) => set((state) => ({
    todos: state.todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ),
  })),
}));

// 使用例
function TodoList() {
  const { todos, addTodo, toggleTodo } = useStore();
  
  return (
    <View>
      <FlatList
        data={todos}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => toggleTodo(item.id)}>
            <Text>{item.text}</Text>
          </TouchableOpacity>
        )}
      />
    </View>
  );
}

希少性: 一般的 難易度:


9. Reduxで副作用をどのように処理しますか?

回答: 非同期操作にはミドルウェアを使用します。

  • Redux Thunk: 関数を返す関数
  • Redux Saga: ジェネレーターベース、より強力
  • Redux Observable: RxJSベース
// Redux Thunk
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_REQUEST' });
  
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const user = await response.json();
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
  } catch (error) {
    dispatch({ type: 'FETCH_USER_FAILURE', payload: error.message });
  }
};

// 使用例
dispatch(fetchUser(123));

// Redux Saga
import { call, put, takeEvery } from 'redux-saga/effects';

function* fetchUserSaga(action) {
  try {
    const user = yield call(fetch, `https://api.example.com/users/${action.payload}`);
    const data = yield call([user, 'json']);
    yield put({ type: 'FETCH_USER_SUCCESS', payload: data });
  } catch (error) {
    yield put({ type: 'FETCH_USER_FAILURE', payload: error.message });
  }
}

function* watchFetchUser() {
  yield takeEvery('FETCH_USER_REQUEST', fetchUserSaga);
}

希少性: 一般的 難易度: 難しい


パフォーマンスの最適化 (5つの質問)

10. FlatListのパフォーマンスをどのように最適化しますか?

回答: 複数の戦略でFlatListのスクロールを改善できます。

  1. keyExtractorを使用: 一意のキーを提供します。
  2. getItemLayout: 固定高さのアイテムの測定をスキップします。
  3. removeClippedSubviews: 画面外のビューをアンマウントします(Android)。
  4. maxToRenderPerBatch: バッチサイズを制御します。
  5. windowSize: レンダリングされるウィンドウを制御します。
  6. initialNumToRender: 最初にレンダリングするアイテム数。
  7. renderItemをメモ化: 不要な再レンダリングを防ぎます。
import React, { memo, useCallback } from 'react';

const ITEM_HEIGHT = 80;

// メモ化されたアイテムコンポーネント
const ListItem = memo(({ item, onPress }) => {
  return (
    <TouchableOpacity onPress={() => onPress(item.id)} style={{ height: ITEM_HEIGHT }}>
      <Text>{item.name}</Text>
    </TouchableOpacity>
  );
});

function OptimizedList({ data }) {
  const handlePress = useCallback((id) => {
    console.log('Pressed:', id);
  }, []);
  
  const renderItem = useCallback(({ item }) => (
    <ListItem item={item} onPress={handlePress} />
  ), [handlePress]);
  
  const keyExtractor = useCallback((item) => item.id.toString(), []);
  
  const getItemLayout = useCallback((data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  }), []);
  
  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      updateCellsBatchingPeriod={50}
      initialNumToRender={10}
      windowSize={5}
    />
  );
}

希少性: 非常に一般的 難易度:


11. React Nativeブリッジとは何ですか?また、パフォーマンスにどのように影響しますか?

回答: ブリッジは、JavaScriptとネイティブコード間の通信レイヤーです。

  • 仕組み:
    • JavaScriptは別のスレッドで実行されます。
    • ネイティブモジュールはネイティブスレッドで実行されます。
    • ブリッジはそれらの間でデータをシリアル化します(JSON)。
  • パフォーマンスへの影響:
    • ブリッジ通信は非同期です。
    • シリアル化のオーバーヘッド
    • 頻繁な通信でボトルネックになる可能性があります。
  • 解決策:
    • ブリッジの交差を最小限に抑えます。
    • バッチ操作
    • ネイティブアニメーションを使用します(ブリッジをバイパスします)。
    • 新しいアーキテクチャ(JSI)はブリッジを削除します。
// 悪い例 - 頻繁なブリッジの交差
const BadAnimation = () => {
  const [position, setPosition] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      setPosition(p => p + 1); // フレームごとにブリッジを交差!
    }, 16);
    return () => clearInterval(interval);
  }, []);
  
  return <View style={{ transform: [{ translateX: position }] }} />;
};

// 良い例 - ネイティブアニメーション(ブリッジなし)
const GoodAnimation = () => {
  const translateX = useRef(new Animated.Value(0)).current;
  
  useEffect(() => {
    Animated.timing(translateX, {
      toValue: 100,
      duration: 1000,
      useNativeDriver: true, // ネイティブスレッドで実行!
    }).start();
  }, []);
  
  return <Animated.View style={{ transform: [{ translateX }] }} />;
};

希少性: 一般的 難易度: 難しい


12. 不要な再レンダリングをどのように防ぎますか?

回答: 複数の手法で無駄なレンダリングを防ぎます。

  1. React.memo: コンポーネントをメモ化します。
  2. useMemo/useCallback: 値/関数をメモ化します。
  3. 適切なキーprops: Reactが変更を識別するのに役立ちます。
  4. インラインオブジェクト/配列を避けます: 新しい参照を作成します。
  5. コンポーネントを分割します: より小さく、焦点を絞ったコンポーネント。
// 悪い例 - レンダリングごとに新しいオブジェクトを作成
function BadComponent() {
  return <ChildComponent style={{ margin: 10 }} />; // 新しいオブジェクト!
}

// 良い例 - 安定した参照
const styles = StyleSheet.create({
  container: { margin: 10 },
});

function GoodComponent() {
  return <ChildComponent style={styles.container} />;
}

// カスタム比較を使用したReact.memo
const ExpensiveComponent = React.memo(
  ({ data, onPress }) => {
    console.log('Rendering ExpensiveComponent');
    return (
      <View>
        <Text>{data.name}</Text>
        <Button onPress={onPress} />
      </View>
    );
  },
  (prevProps, nextProps) => {
    // カスタム比較 - data.idが変更された場合にのみ再レンダリング
    return prevProps.data.id === nextProps.data.id;
  }
);

// コンポーネントを分割して再レンダリングを分離
function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');
  
  return (
    <View>
      {/* countが変更された場合にのみ再レンダリング */}
      <CountDisplay count={count} />
      
      {/* textが変更された場合にのみ再レンダリング */}
      <TextDisplay text={text} />
      
      <Button onPress={() => setCount(c => c + 1)} />
    </View>
  );
}

const CountDisplay = React.memo(({ count }) => <Text>{count}</Text>);
const TextDisplay = React.memo(({ text }) => <Text>{text}</Text>);

希少性: 非常に一般的 難易度:


13. React Nativeで画像をどのように最適化しますか?

回答: 画像の最適化はパフォーマンスにとって非常に重要です。

  1. 画像のサイズを変更: 適切な寸法を使用します。
  2. 画像をキャッシュ: react-native-fast-imageなどのライブラリを使用します。
  3. 遅延読み込み: 必要に応じて画像を読み込みます。
  4. プログレッシブ読み込み: 最初にプレースホルダーを表示します。
  5. WebP形式を使用: より良い圧縮。
import FastImage from 'react-native-fast-image';

function OptimizedImage({ uri }) {
  return (
    <FastImage
      source={{
        uri,
        priority: FastImage.priority.normal,
        cache: FastImage.cacheControl.immutable,
      }}
      resizeMode={FastImage.resizeMode.cover}
      style={{ width: 200, height: 200 }}
    />
  );
}

// プログレッシブ画像の読み込み
function ProgressiveImage({ thumbnailUri, fullUri }) {
  const [imageLoaded, setImageLoaded] = useState(false);
  
  return (
    <View>
      <Image
        source={{ uri: thumbnailUri }}
        style={styles.image}
        blurRadius={imageLoaded ? 0 : 5}
      />
      <Image
        source={{ uri: fullUri }}
        style={[styles.image, { opacity: imageLoaded ? 1 : 0 }]}
        onLoad={() => setImageLoaded(true)}
      />
    </View>
  );
}

// 画像のプリフェッチ
import { Image } from 'react-native';

const prefetchImages = async (urls) => {
  const promises = urls.map(url => Image.prefetch(url));
  await Promise.all(promises);
};

希少性: 一般的 難易度:


14. パフォーマンスプロファイリングにはどのようなツールを使用しますか?

回答: 複数のツールがパフォーマンスの問題を特定するのに役立ちます。

  • React DevTools Profiler: コンポーネントのレンダリング時間
  • Flipper: デバッグおよびプロファイリングツール
  • Performance Monitor: 組み込みのFPSモニター
  • Systrace: Androidのパフォーマンストレース
  • Instruments: iOSのパフォーマンスプロファイリング
// 開発時にパフォーマンスモニターを有効にする
import { LogBox } from 'react-native';

if (__DEV__) {
  // パフォーマンスモニターを表示
  require('react-native').unstable_enableLogBox();
}

// コンポーネントのレンダリング時間を測定
import { Profiler } from 'react';

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime
) {
  console.log(`${id} (${phase}) took ${actualDuration}ms`);
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MyComponent />
    </Profiler>
  );
}

// カスタムパフォーマンストラッキング
const measurePerformance = (name, fn) => {
  const start = performance.now();
  const result = fn();
  const end = performance.now();
  console.log(`${name} took ${end - start}ms`);
  return result;
};

希少性: 一般的 難易度:


ネイティブモジュールとプラットフォーム固有 (4つの質問)

15. React Nativeでネイティブモジュールをどのように作成しますか?

回答: ネイティブモジュールを使用すると、プラットフォーム固有のコードを使用できます。

// iOS (Objective-C) - CalendarManager.m
#import "CalendarManager.h"
#import <React/RCTLog.h>

@implementation CalendarManager

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
  RCTLogInfo(@"Creating event %@ at %@", name, location);
}

@end

// Android (Java) - CalendarModule.java
package com.myapp;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class CalendarModule extends ReactContextBaseJavaModule {
  CalendarModule(ReactApplicationContext context) {
    super(context);
  }

  @Override
  public String getName() {
    return "CalendarManager";
  }

  @ReactMethod
  public void addEvent(String name, String location) {
    Log.d("CalendarModule", "Creating event " + name + " at " + location);
  }
}

// JavaScriptでの使用
import { NativeModules } from 'react-native';

const { CalendarManager } = NativeModules;

function MyComponent() {
  const createEvent = () => {
    CalendarManager.addEvent('Meeting', 'Office');
  };
  
  return <Button title="Create Event" onPress={createEvent} />;
}

希少性:難易度: 難しい


16. プラットフォーム固有のコードをどのように処理しますか?

回答: プラットフォーム固有のコードには複数のアプローチがあります。

  1. Platformモジュール: 実行時にプラットフォームを確認します。
  2. プラットフォーム固有のファイル: .ios.jsおよび.android.js
  3. Platform.select: プラットフォームに基づいて値を選択します。
import { Platform } from 'react-native';

// Platformモジュール
const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 20 : 0,
  },
});

// Platform.select
const styles = StyleSheet.create({
  container: {
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.3,
      },
      android: {
        elevation: 4,
      },
    }),
  },
});

// プラットフォーム固有のファイル
// Button.ios.js
export default function Button() {
  return <Text>iOS Button</Text>;
}

// Button.android.js
export default function Button() {
  return <Text>Android Button</Text>;
}

// 使用法 - 正しいファイルが自動的に選択されます
import Button from './Button';

// プラットフォームバージョンの確認
if (Platform.Version >= 21) {
  // Android API 21+
}

希少性: 非常に一般的 難易度: 簡単


17. 新しいアーキテクチャ(FabricとTurboModules)とは何ですか?

回答: 新しいアーキテクチャは、React Nativeのパフォーマンスを向上させます。

  • Fabric: 新しいレンダリングシステム
    • 同期レイアウト
    • ネイティブビューとのより良い相互運用性
    • 型安全性
  • TurboModules: 新しいネイティブモジュールシステム
    • 遅延読み込み
    • JSI(JavaScript Interface)- C++との直接通信
    • ブリッジシリアル化なし

利点:

  • より速い起動
  • より低いメモリ使用量
  • 同期的なネイティブ呼び出し
  • より良い型安全性

希少性:難易度: 難しい


18. React Nativeでディープリンクをどのように処理しますか?

回答: ディープリンクを使用すると、URLから特定の画面を開くことができます。

import { Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';

// ディープリンクを構成
const linking = {
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: 'home',
      Profile: 'profile/:id',
      Settings: 'settings',
    },
  },
};

function App() {
  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

// 受信リンクの処理
useEffect(() => {
  const handleUrl = ({ url }) => {
    console.log('Opened with URL:', url);
    // myapp://profile/123
  };
  
  // リンクからアプリを開く
  Linking.getInitialURL().then(url => {
    if (url) handleUrl({ url });
  });
  
  // アプリはすでに開いており、新しいリンク
  const subscription = Linking.addEventListener('url', handleUrl);
  
  return () => subscription.remove();
}, []);

// プログラムでURLを開く
const openURL = async (url) => {
  const supported = await Linking.canOpenURL(url);
  if (supported) {
    await Linking.openURL(url);
  }
};

希少性: 一般的 難易度:


テスト (3つの質問)

19. React Nativeコンポーネントをどのようにテストしますか?

回答: JestやReact Native Testing Libraryなどのテストライブラリを使用します。

import { render, fireEvent, waitFor } from '@testing-library/react-native';
import Counter from './Counter';

describe('Counter', () => {
  it('renders initial count
Newsletter subscription

実際に機能する週次のキャリアのヒント

最新の洞察をメールボックスに直接お届けします

応募をやめて、採用されよう。

世界中の求職者に信頼されているAI搭載の最適化で、履歴書を面接の磁石に変えましょう。

無料で始める

この投稿を共有

履歴書作成時間を90%短縮

平均的な求職者は履歴書のフォーマットに3時間以上費やしています。当社のAIは15分以内で完成させ、応募段階に12倍速く到達できます。