< Back

WebエンジニアがReactNative触ってみたのでつまづきポイント書いていく

Reactは最低限書けますが、 「なんかViewとか新しいComponentでてきてとっつきにくいな」とずっと避けていたので今年ちゃんと入門しようと思って書いてます。

わかってしまったら結構簡単だったので普段からReact書いている人は少しだけでもいいので書いてみると楽しいかもです。

Reactエンジニアってよくわからないですが、普段からReact触っていて基本は抑えている人のことと仮定してます。もっというと

の「Reactを学ぶ」の部分は抑えている人のこと

React Native = React - HTML + Core Components

自分は React Native書いていて <View> みたいなフロント描画するところがすぐには馴染めなかったです。div, p, spanとかWebにある当たり前のComponentがなくて Core Components と呼ばれるものしかなかったです。

一旦入門して数日の雑な理解です。

Core Components とそれぞれのNativeのComponentsの対応

このページを読めば完全理解できます。

REACT NATIVE UI COMPONENT ANDROID VIEW IOS VIEW WEB ANALOG DESCRIPTION
<View> <ViewGroup> <UIView> A non-scrolling <div> A container that supports layout with flexbox, style, some touch handling, and accessibility controls
<Text> <TextView> <UITextView> <p> Displays, styles, and nests strings of text and even handles touch events
<Image> <ImageView> <UIImageView> <img> Displays different types of images
<ScrollView> <ScrollView> <UIScrollView> <div> A generic scrolling container that can contain multiple components and views
<TextInput> <EditText> <UITextField> <input type=text> Allows the user to enter text

たぶんこれはAndroid および iOS 用の独自のネイティブ コンポーネントに対応しているので、iOSをSwiftで書いたり、AndroidをKotlinで書いたり、Flutter を使ったりする上でかなり約立つ知識だと思うのでこの際に勉強できてよかったです。

練習方法

このTypeScript導入の記事で書かれているスクリプトで作成できます。

npx create-expo-app --template

ReactNativeはWebでも確認できるのでPC上でソースコードを書き、Webブラウザを確認し、Hot Module Replacementを使って自動で再レンダリングされるので開発やりやすかったです。

Reactの基本ができている人は divとViewの対応みたいなところだけを抑えたらOKなので、基本は写経しましょう。

  • Introduction
  • Core Components and Native Components
  • React Fundamentals (React使いはほぼ読まなくてよい)
  • Handling Text Input
  • Using a ScrollView
  • Using List Views

これすべて写経しても200行も行かなかったので、普段から大きめなReactComponent書いている人は全然2時間もかからないと思います。

私が書いたコード全量
import React, { useState } from 'react';
import { Button, ScrollView, StyleSheet, Image, TextInput, FlatList, SectionList } from 'react-native';

import { Text, View } from './Themed';

const HelloWorldApp = () => {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <Text>Hello, World!</Text>
    </View>
  )
};

const Greeting = ({ name }: { name: string }) => {
  return (
    <View
      style={styles.center}
    >
      <Text>Hello {name}!</Text>
    </View>
  )
}
const ClickButtonContainer = () => {
  const [count, setCount] = useState(0);

  return (
    <View
      style={styles.center}
    >
      <Text>Click me follow button! Num: {count}</Text>
      <Button
        onPress={() => setCount((prev) => prev + 1)}
        title="Click me!"
      />
    </View>
  )
}
const EditingApp = () => {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <Text>Try editing me!</Text>
    </View>
  )
}
const CatApp = () => {
  return (
    <ScrollView>
      <Text>Some Text</Text>
      <View>
        <Text>Some more text</Text>
        <Image
          source={{ uri: "https://source.unsplash.com/random" }}
          style={{ width: 200, height: 200 }}
        />
      </View>
      <TextInput
        style={{
          height: 40,
          borderColor: "gray",
          borderWidth: 1,
        }}
        defaultValue="Write me"
      />
    </ScrollView>
  )
}
const PizzaTranslator = () => {
  const [text, setText] = useState('');
  return (
    <View
      style={{ padding: 10 }}
    >
      <TextInput
        style={{ height: 40 }}
        placeholder='Type Here to translate!'
        onChangeText={text => setText(text)}
        defaultValue={text}
      />
      <Text
        style={{ padding: 10, fontSize: 42 }}
      >
        {text.split(' ').map(word => word && '🍕').join(' ')}
      </Text>

    </View>
  )
}

const UsingScrollView = () => {
  const logo = {
    uri: 'https://source.unsplash.com/random',
    width: 120,
    height: 120,
  };

  return (
    <ScrollView style={{ height: 300 }}>
      <Text style={{ fontSize: 96 }}>Scroll me plz</Text>
      <Image source={logo} />
      <Image source={logo} />
    </ScrollView>
  )
}

const FlatListBasics = () => {
  return (
    <View style={{
      flex: 1,
      paddingTop: 22,
    }}>
      <FlatList
        data={[
          { key: 'Devin' },
          { key: 'Dan' },
          { key: 'Dominic' },
          { key: 'Jackson' },
          { key: 'James' },
          { key: 'Joel' },
          { key: 'John' },
          { key: 'Jillian' },
          { key: 'Jimmy' },
          { key: 'Julie' },
        ]}
        style={{
          borderWidth: 1,
          borderColor: 'gray',
        }}
        renderItem={({ item }) => {
          return <Text>{item.key}</Text>
        }}
      />
    </View>
  );
}
const SectionListBasics = () => {
  const sections = [
    { title: 'D', data: ['Devin', 'Dan', 'Dominic'] },
    { title: 'J', data: ['Jackson', 'James', 'Jillian', 'Jimmy'] }
  ]
  return (
    <View style={styles.container}>
      <SectionList
        sections={sections}
        renderItem={({ item }) => {
          return <Text>{item}</Text>
        }}
        renderSectionHeader={({ section }) => (
          <Text style={styles.sectionHeader}>{section.title}</Text>
        )}
        keyExtractor={item => `basicListEntry-${item}`}
      />
    </View>
  )
}

export function PracticeScreenMain() {
  return (
    <ScrollView>
      <UsingScrollView />
      <FlatListBasics />
      <SectionListBasics />
      <View>
        <View style={styles.getStartedContainer}>
          <Text
            style={styles.getStartedText}
            lightColor="rgba(0,0,0,0.8)"
            darkColor="rgba(255,255,255,0.8)">
            Practice Screen Main
          </Text>
        </View>
        <View>
          <HelloWorldApp />
          <Greeting name="tanaka" />
          <Greeting name="goro" />
          <ClickButtonContainer />
          <EditingApp />
          <CatApp />
          <PizzaTranslator />
        </View>
      </View>
    </ScrollView>
  );
}

const Split3 = () => (
  <View
    style={{
      flex: 1,
      padding: 20,
      width: '100%',
      flexDirection: 'column',
    }}
  >
    <View style={{ flex: 1, backgroundColor: 'powderblue' }} />
    <View style={{ flex: 2, backgroundColor: 'blue' }} />
    <View style={{ flex: 3, backgroundColor: 'red' }} />
  </View>);

const SplitLayout = () => {
  return (
    <View>
      <Text>ts</Text>
    </View>
  )
}


export function PracticeScreenSub() {
  return (
    <SplitLayout />
  );
}

const styles = StyleSheet.create({
  center: {
    alignItems: 'center',
  },
  getStartedContainer: {
    alignItems: 'center',
    marginHorizontal: 50,
  },
  getStartedText: {
    fontSize: 17,
    lineHeight: 24,
    textAlign: 'center',
  },
  container: {
    flex: 1,
    paddingTop: 22,
  },
  sectionHeader: {
    paddingTop: 2,
    paddingLeft: 10,
    paddingRight: 10,
    paddingBottom: 2,
    fontSize: 14,
    fontWeight: 'bold',
    backgroundColor: 'rgba(247,247,247,1.0)',
  },
  item: {
    padding: 10,
    fontSize: 18,
    height: 44,
  },
});

ここまでやれば「なんか新しいComponentでてきてとっつきにくいな」という感情はなくなってくるので、後は必要なところだけ調べて書いていくだけになるのでぜひ写経を試していください。

CSS

普段からstyled-componentsを使っている人は使ったほうが無難だと思います。6系はStylus関連でエラー出るので一旦5系にした

npm i --save styled-components@5

これがReactNativeっぽい書き方。
利用していないCSSがあったとしてもエラーにならないし自分は慣れてないです。

export const PracticeScreen = () => {
  return (
    <View style={styles.container}>
      <PracticeScreenMain />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

StyledComponentの書き方。慣れている人にはなれている。

const Container = styled.View`
  flex: 1;
  align-items: 'center',
  justify-content: 'center',
`;

export const StyledScreen = () => {
  return (
    <Container>
      <PracticeScreenMain />
    </Container>
  );
}

まとめ

自分的にはNativeのComponentとHTMLの突合を理解するために写経をやって、styledを入れたらほぼいつも通りの使い心地でコードを書くことができました。