React Native 勉強

基本的に↓の動画で勉強
動画ではexpoだけど自分はios simulatorでやってみる。

eslintのインストール、設定
$ npm install eslint --save-dev
$ npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
Need to install the following packages:
@eslint/create-config
Ok to proceed? (y) y
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ What format do you want your config file to be in? · JavaScript
The config that you've selected requires the following dependencies:
@typescript-eslint/eslint-plugin@latest eslint-plugin-react@latest @typescript-eslint/parser@latest
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm
$ npm i @react-native-community/eslint-config --save-dev
.eslint.jsのextendsを以下に変更
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
+ "@react-native-community"
],
rulesを以下に変更
"rules": {
+ semi: ["error", "never"],
+ 'comma-dangle': ['2', 'never'],
+ 'react/jsx-filename-extendsion': [1, { extensions: ['.ts', '.tsx'] }],
+ 'no-use-before-define': [
+ 'error',
+ { functions: false, classes: true, variables: false },
+ ],
}
package.jsonのsctiptsを以下に変更
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
+ "lint": "eslint"
},

prettier(コードフォーマット整形)のインストール、設定
$ npm i --save-dev --sage-exact prettier
$ touch .prettierc.js
.prettierc.jsの中身
module.exports = {
brancketSpacing: true,
singleQuote: true,
tabWidth: 2,
useTabs: false,
trailingComma: 'none',
semi: false,
};

アイコンで挫折
expoだと最初から"@expo/vector-icon"があるけどexpoじゃないから、"react-native-vector-icon"をnpm installして↓のサイトを参考に設定した。
そしたら↓のエラーが出てググっても分からなかった。
ERROR Invariant Violation: "remaind_me" has not been registered. This can happen if:
* Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project.
* A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called., js engine: hermes
一旦expoに切り替えて解決

ViewコンポーネントはHTMLでいうdivタグみたいな感じ
<View>
<Text></Text>
</View>
SafeAreaViewを使うと、iOSの下のバーとかに自動的にpaddingをつけてくれる。
<SafeAreaView>
<Text></Text>
</SafeAreaView>

Flatlist
いい感じにリストを作成するためのコンポーネント。
dataプロパティにリストにしたい配列を渡して、renderItemプロパティに渡したコンポーネントに配列の要素を一つずつ渡す。
実際に表示されるのはrenderItemプロパティに渡したコンポーネント。
keyExtractorに固有のidを渡すのはreact nativeが各項目を追跡できるようにするため。(リスト内の項目に変更があった際のレンダリング効率を上げるため)
ItemSeparatorComponentで各項目間の仕切りみたいなのを作れる。
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
type ItemProps = {title: string};
const Item = ({title}: ItemProps) => (
<View>
<Text>{title}</Text>
</View>
);
const App = () => {
return (
<SafeAreaView>
<FlatList
data={DATA}
renderItem={({item}) => <Item title={item.title} />}
keyExtractor={item => item.id}
ItemSeparatorComponent={() => <View style={{backgroundColor: 'red', height: 2}} />}
/>
</SafeAreaView>
);
};
その他プロパティは以下のリンク

renderItemに渡すものはApp()内で変数に格納した方がFlatListコンポーネント自体はスッキリ書ける。

画像関係
Image
画像を表示するためにコアコンポーネント。
ネットワーク画像とデータ画像の場合は、自分で寸法を設定する。
<Image
source={require("../../assets/upcoming-background.jpg")}
style={styles.img}
/>
sourseに表示する画像のパス、もしくはurlなど。
ImageBackground
このコンポーネントの中に配置したコンポーネントの背景がsourseプロパティに入れた画像になる。
<SafeAreaView style={styles.container}>
<ImageBackground
source={require("../../assets/upcoming-background.jpg")}
style={styles.img}
>
<Text>Upcoming Weather</Text>
</ImageBackground>
</SafeAreaView>

style
コアコンポーネントに渡すstyleは配列で渡せる。共通styleと独自styleで分ければコード削減に繋がる。
<Text style={[styles.cityName, styles.cityText]}>London</Text>
<Text style={[styles.countryName, styles.cityText]}>UK</Text>
const styles = StyleSheet.create({
cityName: {
fontSize: 40,
},
countryName: {
fontSize: 30,
},
cityText: {
justifyContent: "center",
alignSelf: "center",
fontWeight: "bold",
color: "white",
},
});

navigation
必要なパッケージをインストール
$ npm i @react-navigation/native @react-navigation/bottom-tabs
$ npx expo install react-native-screens react-native-safe-area-context
以下のようにすることでページ遷移させるタブを実装できる
import React from "react";
import { View, StyleSheet } from "react-native";
import CurrentWeather from "./src/screen/CurrentWeather";
import UpcomingWeather from "./src/screen/UpcomingWeather";
import City from "./src/screen/City";
import { NavigationContainer } from "@react-navigation/native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
const Tab = createBottomTabNavigator();
const App = () => {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={{
tabBarActiveTintColor: "tomato",
tabBarInactiveTintColor: "gray",
tabBarStyle: {
backgroundColor: "lightblue",
},
headerStyle: {
backgroundColor: "lightblue",
},
headerTitleStyle: {
fontWeight: "bold",
fontSize: 25,
color: "tomato",
},
}}
>
<Tab.Screen
name={"Current"}
component={CurrentWeather}
options={{
tabBarIcon: ({ focused }) => (
<Feather
name={"droplet"}
size={25}
color={focused ? "tomato" : "black"}
/>
),
}}
/>
<Tab.Screen
name={"Upcoming"}
component={UpcomingWeather}
options={{
tabBarIcon: ({ focused }) => (
<Feather
name={"clock"}
size={25}
color={focused ? "tomato" : "black"}
/>
),
}}
/>
<Tab.Screen
name={"City"}
component={City}
options={{
tabBarIcon: ({ focused }) => (
<Feather
name={"home"}
size={25}
color={focused ? "tomato" : "black"}
/>
),
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
};
Tab.Navigator
tabBarActiveTintColor: 現在のタブの色
tabBarInactiveTintColor: その他のタブの色
tabBarStyle: タブ全体にスタイルを当てられる
headerStyle: ヘッダーにスタイルを当てられる
headerTitleStyle: ヘッダーのタイトル文字にスタイルを当てられる
Tab.Screen
options: tabBarIconでタブアイコンを設定できる。focusedは現在そのタブにいるかどうか

ボタン
コアコンポーネントのButtonが使える。
counst Counter = () => {
let counnt = 0;
return (
<View>
<Button
color={'red'}
title={'Increase the count'}
onPress={() => {
count ++
console.log(count)
}}
/>
</View>
)
}
color: 色変えれる
title: ボタンに文字つけれる
onPress: タップ時の処理を与えられる
↑のコード例だとcountの表示は変わらないからstateを使わないとダメ

ローディング画面
コアコンポーネントのActivityIndicatorが使える。
import { ActivityIndicator } from "react-native";
const App = () => {
if (loading) {
return (
<View style={styles.container}>
<ActivityIndicator size="large" color="blue" />
</View>
);
}
return (
<NavigationContainer>
<View></View>
</NavigationContainer>
);
}