ksg

ksg@software_engineer

Portfolio Blog

reactnative2026/10/30

ReactとReact Nativeの違いをコードで比較【Web開発者向け】

ReactとReact Nativeの違いをコードで比較【Web開発者向け】

この記事は「Reactは少しわかるけど、React Nativeは初めて」という人向けです

React Nativeは、Webサイトを作るための「React」と考え方がほぼ同じです。そのため、Reactを知っている人は、React Nativeをすぐに使い始められます。

ただ、実際に書き始めると、「div が使えない」「CSSが効かない」「並び方が逆になった」のように、Webの感覚のままだと戸惑うところがいくつもあります。

この記事では、

  • ReactとReact Nativeで 同じところ
  • ReactとReact Nativeで 違うところ(部品、スタイル、レイアウト、イベント、画面遷移、保存、公開など)
  • Webの知識で書いたときに つまずきやすいポイント

を、コードを比べながら説明します。React Nativeをゼロから学びたい人は、先に入門シリーズの第1回から読むのがおすすめです。

ひとことで言うと

考え方は同じ。画面に出す部品と、見た目の付け方と、動く場所が違う。

料理にたとえると、ReactもReact Nativeも「同じレシピ(考え方)」を使います。でも、Reactは「ガスコンロ(ブラウザ)」で、React Nativeは「IHコンロ(スマホ)」で料理をします。レシピは同じでも、使える鍋(部品)や火加減の調整方法(スタイル)が少し違う、というイメージです。

同じところ

まずは、そのまま使える知識からです。

  • コンポーネントは「画面の中身を返す関数」
  • propsで部品に情報を渡す
  • useState、useEffect、useMemo などのフック
  • 配列を map で一覧にして、key を付ける
  • JSXで書く
  • TypeScriptが使える

たとえば、ボタンを押すと数字が増えるカウンターを比べてみましょう。

React(Web)

import { useState } from "react";

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

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

React

import { useState } from "react";
import { Pressable, Text, View } from "react-native";

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

  return (
    <View>
      <Text>{count}</Text>
      <Pressable onPress={() => setCount(count + 1)}>
        <Text>+1</Text>
      </Pressable>
    </View>
  );
}

useState の使い方や、count を表示する書き方はまったく同じです。違うのは、div が View に、p が Text に、button が Pressable に、onClick が onPress に変わっているところだけです。

ここからは、この「違うところ」を1つずつ見ていきます。

違い1: 部品(HTMLのタグは使えない)

React Nativeでは、div や p のような HTMLのタグは使えません。書くとエラーになります。代わりに、React Nativeが用意している部品(コンポーネント)を使います。

React(Web)

React Native

役割

div、section

View

部品をまとめる箱

p、span、h1

Text

文字

img

Image

画像

button

Pressable

押せる場所

input、textarea

TextInput

文字の入力

ul + li

FlatList

一覧

(ページのスクロール)

ScrollView

スクロールできる場所

a

Link(Expo Router)

別の画面へのリンク

文字は必ず Text の中に書く

Webでは、<div>こんにちは</div> のように、どこにでも文字を書けました。React Nativeでは、文字は必ず Text の中に書く 必要があります。

// ✕ エラーになる
<View>こんにちは</View>

// ○ 正しい
<View>
  <Text>こんにちは</Text>
</View>

見出しの h1 や h2 はない

h1 のような「見出し用のタグ」もありません。見出しは、Text に大きな fontSize と太い fontWeight を付けて作ります。

画像は大きさを指定する

Webの img は、大きさを書かなくても、画像の元の大きさで表示されます。React Nativeの Image でインターネット上の画像を表示するときは、width と height を指定しないと表示されません。

<Image source={{ uri: "https://example.com/photo.png" }} style={{ width: 120, height: 120 }} />

違い2: スタイル(CSSファイルは使えない)

classNameではなく、JavaScriptのオブジェクトで書く

Webでは、CSSファイルにスタイルを書いて、className で付けるのが基本でした。React Nativeでは、CSSファイルは使えません。スタイルはJavaScriptのオブジェクトとして書き、style で付けます。

Web(CSS)

.title {
  font-size: 24px;
  font-weight: bold;
  background-color: #e0f2fe;
}

React

const styles = StyleSheet.create({
  title: {
    fontSize: 24,
    fontWeight: "bold",
    backgroundColor: "#e0f2fe",
  },
});

<Text style={styles.title}>タイトル</Text>

書き方のルールは3つです。

  • font-size ではなく fontSize のように、ハイフンをなくして、2つ目の単語の頭を大文字にする
  • 数字に 単位(px など)を付けない。24 と書けば、端末に合った大きさになる
  • 値が文字のときは "bold" のように " " で囲む

スタイルは親から子に引き継がれない

ここはWebの感覚だと一番つまずきやすいところです。

Webでは、body に color: red を書くと、中の文字が全部赤くなりました。スタイルが親から子に 引き継がれる(継承される) からです。

React Nativeでは、View に付けた文字のスタイルは、中の Text に引き継がれません。

// ✕ 文字は赤くならない(Viewには文字の色を付けられない)
<View style={{ color: "red" }}>
  <Text>こんにちは</Text>
</View>

// ○ Textに直接付ける
<View>
  <Text style={{ color: "red" }}>こんにちは</Text>
</View>

例外として、Text の中の Text には、スタイルが引き継がれます。文章の一部だけを太字にしたいときに便利です。

<Text style={{ color: "red" }}>
  これは<Text style={{ fontWeight: "bold" }}>大事</Text>なことです
</Text>

この例では、「大事」の部分も赤くなり、さらに太字になります。

:hover やメディアクエリはない

CSSの :hover(マウスを乗せたとき)や、@media(画面の幅で見た目を変える)も使えません。スマホにはマウスがないので、:hover の代わりに「押している間」の見た目を変えます。

<Pressable style={({ pressed }) => [styles.button, pressed && { opacity: 0.6 }]}>
  <Text>押してね</Text>
</Pressable>

Pressable の style に関数を渡すと、pressed(押されているかどうか)を受け取れます。

画面の幅によって見た目を変えたいときは、useWindowDimensions で画面の大きさを取得して、自分で切りかえます。

import { useWindowDimensions } from "react-native";

const { width } = useWindowDimensions();
const columns = width > 600 ? 3 : 2;

iPhoneとAndroidで見た目を変えたいとき

React Nativeならではの機能として、Platform を使うと、iPhoneとAndroidでスタイルを変えられます。

import { Platform } from "react-native";

const styles = StyleSheet.create({
  card: {
    padding: 16,
    ...Platform.select({
      ios: { shadowOpacity: 0.2, shadowRadius: 8 },
      android: { elevation: 4 },
    }),
  },
});

影の付け方は、iPhone(shadow〇〇)とAndroid(elevation)で書き方が違う代表例です。

違い3: レイアウト(Flexboxが基本で、縦並びが初期値)

何も書かなくてもFlexbox

Webでは、Flexboxを使いたいときに display: flex を書きました。React Nativeでは、すべての View が最初からFlexbox です。display: flex を書く必要はありません。CSSの grid は使えないので、並べ方はFlexboxで考えます。

初期値は縦並び

Webの display: flex は、何も書かないと 横に 並びます(flex-direction: row)。React Nativeは、何も書かないと 縦に 並びます(flexDirection: "column")。

// 横に並べたいときは、はっきり書く
<View style={{ flexDirection: "row" }}>
  <Text>左</Text>
  <Text>右</Text>
</View>

そのほかの細かい違い

Webのつもりで書くと、少しずつ動きが違うところがあります。

項目

Web(CSS)

React Native

flexDirection の初期値

row(横)

column(縦)

flexShrink の初期値

1(はみ出しそうなら縮む)

0(縮まない)

flex

flex: 1 1 0 のように複数の値を書ける

数字1つだけ(flex: 1)

position の初期値

static

relative

特に flexShrink は、「横に並べた文字が画面からはみ出す」原因になりがちです。長い文字を横に並べるときは、文字の側に flex: 1 や flexShrink: 1 を付けると、画面の中で折り返してくれます。

違い4: イベント(onClickではなくonPress)

やりたいこと

React(Web)

React Native

押したとき

onClick

onPress

長押ししたとき

(標準ではない)

onLongPress

文字が変わったとき

onChange

onChangeText

文字の入力では、受け取り方も違います。

React(Web)

<input value={name} onChange={(event) => setName(event.target.value)} />

React

<TextInput value={name} onChangeText={setName} />

Webの onChange では、event.target.value から入力された文字を取り出しました。React Nativeの onChangeText には、入力された文字がそのまま届く ので、setName をそのまま渡せます。

また、TextInput には、スマホならではの設定がたくさんあります。

<TextInput
  keyboardType="number-pad" // 数字のキーボードを出す
  secureTextEntry // パスワードのように ●●● で隠す
  autoCapitalize="none" // 最初の文字を自動で大文字にしない
/>

違い5: スクロールと一覧

Webでは、中身が画面より長くなると、ページ全体が自動でスクロール しました。React Nativeでは、自動ではスクロールしません。スクロールさせたい場所を、ScrollView か FlatList で囲む必要があります。

  • ScrollView: 中身を一度に全部作る。量が少ないとき向け
  • FlatList: 画面に見えている部分だけを作る。一覧のデータが多いとき向け

Webで ul と li を map で並べていたような一覧は、React Nativeでは基本的に FlatList を使います。

<FlatList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <Text>{item.title}</Text>}
/>

違い6: 画面遷移(URLではなく、画面を重ねる)

考え方の違い

Webの画面遷移は、URLを切りかえる 仕組みです。ブラウザの「戻る」ボタンを押すと、1つ前のURLに戻ります。

スマホアプリの画面遷移は、画面をトランプのように上に重ねていく 仕組み(スタック)が基本です。新しい画面は今の画面の上に重なり、「戻る」を押したり、画面のはしから横にスワイプしたりすると、一番上の画面が取りのぞかれます。画面の下にボタンが並ぶ タブ もよく使われます。

Expo RouterはNext.jsのApp Routerに近い

Expoでは、Expo Router で画面遷移を作ります。Expo Routerは「app フォルダにファイルを作ると、それが画面になる」仕組みなので、Next.jsのApp Routerを知っている人には、なじみやすい書き方です。

Next.js(App Router)

Expo Router

画面

app/about/page.tsx

app/about.tsx

動的な画面

app/fruits/[id]/page.tsx

app/fruits/[id].tsx

外わく

app/layout.tsx

app/_layout.tsx

リンク

<Link href="/about">

<Link href="/about">

値の受け取り

params

useLocalSearchParams()

戻ってきたときに、画面は作り直されない

ここもWebの感覚だとつまずきやすいところです。

スタックでは、新しい画面に移動しても、下の画面は消えずに残っています。そのため、詳しい画面から一覧の画面に戻ってきても、一覧の画面は作り直されず、useEffect(() => { ... }, []) も もう一度は動きません。

「戻ってきたら一覧を読みこみ直したい」ときは、画面が表示されるたびに動く useFocusEffect を使います。

import { useFocusEffect } from "expo-router";
import { useCallback } from "react";

useFocusEffect(
  useCallback(() => {
    loadItems(); // 画面が表示されるたびに読みこみ直す
  }, []),
);

違い7: 保存とスマホの機能

localStorageではなくAsyncStorage

Webでは、ちょっとしたデータの保存に localStorage を使いました。React Nativeには localStorage がないので、AsyncStorage を使います。

React(Web)

localStorage.setItem("name", "たろう");
const name = localStorage.getItem("name");

React

import AsyncStorage from "@react-native-async-storage/async-storage";

await AsyncStorage.setItem("name", "たろう");
const name = await AsyncStorage.getItem("name");

名前のとおり、AsyncStorageは 非同期(Async) なので、await で終わるのを待つ必要があります。また、パスワードやログインの情報のような、人に見られたくないデータは、AsyncStorageではなく、暗号化して保存してくれる expo-secure-store を使います。

スマホの機能が使える

Webではほとんど使えなかった、スマホの機能を使えるのは、React Nativeの大きな強みです。

  • カメラ、写真の選択(expo-camera、expo-image-picker)
  • 通知(expo-notifications)
  • 位置情報(expo-location)
  • 振動(expo-haptics)

こうした機能を使うときは、多くの場合、ユーザーに許可をもらう 必要があります。「カメラへのアクセスを許可しますか?」というあの画面です。

違い8: 使えるライブラリ

npmのライブラリの多くは、React Nativeでも使えます。ただし、ブラウザの仕組み(window や document、HTMLのタグ)に頼っているライブラリは動きません。

ライブラリの種類

React Nativeで使えるか

計算やデータを扱うもの(日付の計算、状態管理のZustandなど)

使えることが多い

画面の部品のライブラリ(Webの部品集など)

使えない。React Native用のものを探す

CSSのライブラリ

使えない。Tailwindの書き方をしたいなら、NativeWindなどのReact Native用のものを使う

ライブラリを入れるときは、npm install ではなく npx expo install を使うと、今のExpoのバージョンに合うものを選んでくれます。

違い9: 動作確認とデバッグ

React(Web)

React Native(Expo)

動作確認

ブラウザで開く

Expo Goアプリ、シミュレーター、実機

console.log の表示先

ブラウザの開発者ツール

ターミナル

開発者ツール

ブラウザの開発者ツール

React Native DevTools(npx expo start の画面で j キーを押すと開く)

要素の確認

開発者ツールで、HTMLやCSSを直接見られる

DevToolsで、コンポーネントの中身を見られる

Webのように「開発者ツールでCSSを直接いじって試す」ことはできないので、スタイルはコードを書きかえて、Fast Refresh(保存するとすぐに反映される仕組み)で確認しながら調整します。

違い10: 公開と更新

Webサイトは、サーバーに置けばすぐにみんなが見られます。直したいときも、サーバーのファイルを入れかえれば、次に開いた人から新しい内容になります。

スマホアプリは、App StoreやGoogle Playの審査 を通らないと、みんなに使ってもらえません。審査には、数時間から数日かかることがあります。そして、ユーザーがアプリを更新してくれるまでは、古いバージョンが使われ続けます。

そのため、スマホアプリでは、

  • 公開する前のテスト をWebよりしっかりする(iPhoneならTestFlightで、配る前に実機で試せる)
  • 古いバージョンのアプリが残ることを考えて作る(サーバー側の仕組みを急に変えない)

といったことが大切になります。

なお、Expoには EAS Update という仕組みがあり、JavaScriptのコードの修正なら、ストアの審査を通さずにアプリへ届けられます。ただし、新しいスマホの機能を追加するときのように、アプリ本体(ネイティブの部分)を変えるときは、ストアでの更新が必要です。

Webとスマホで、コードを共有できる?

ExpoとReact Nativeは、Webで動かすこともできます(npx expo start の画面で w キーを押すと、ブラウザで開けます)。ただ、最初から「1つのコードで、Webもスマホも完璧に」を目指すと、細かい違いに苦労しがちです。

まずは、画面の部品はそれぞれで作り、ロジック(計算、データの取得、状態管理など)を共有する と考えるのが現実的です。フックや関数は、View や div を使わない限り、ReactでもReact Nativeでも同じように動きます。

まとめ

項目

React(Web)

React Native

考え方(コンポーネント、props、state、フック)

同じ

同じ

部品

div、p、img、button、input

View、Text、Image、Pressable、TextInput

文字

どこにでも書ける

Text の中だけ

スタイル

CSS、className

StyleSheet、style。単位なし

スタイルの継承

親から子に引き継がれる

引き継がれない(Text の中の Text だけ例外)

並べ方

display: flex で横並び

最初からFlexboxで縦並び

イベント

onClick、onChange

onPress、onChangeText

スクロール

ページが自動でスクロール

ScrollView、FlatList で囲む

画面遷移

URLを切りかえる

画面を重ねる(スタック)、タブ

保存

localStorage

AsyncStorage(await が必要)

スマホの機能

ほとんど使えない

カメラ、通知、位置情報などが使える

公開

サーバーに置けばすぐ

ストアの審査が必要

Reactを知っている人は、「考え方はそのまま、部品とスタイルを覚え直す」つもりで始めると、スムーズにReact Nativeを使えるようになります。

React Nativeをゼロから、手を動かしながら学びたい人は、入門シリーズも読んでみてください。

https://ksg-my-portfolio.com/blog/rn-01-intro-setup

おすすめの記事