React Nativeでお知らせを表示する

<h1>（１）はじめに</h1>

<p>普段はソーシャルワーカーとして障がいをお持ちの方の支援をしています。今回はアプリ内のお知らせ表示について書き留めておきたいと思います。運営からのお知らせやアップデートのお知らせなどが、アプリに表示され未読マークがていることがありますよね。どのように実装されているかをイメージしながら作成しました。設定やデータはそれぞれ個人の端末に保存されるという前提で、配信されるお知らせを読んでいない場合は「未読」を表示したいと思います。</p>

![20211216_231231.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635004/554f6595-d671-195f-3068-03a9c878d7f6.gif)

<h1>（２）使った技術</h1>

<p>
・react-native<br>
・expo 42.0.1<br>
・firebase 8.2.3<br>
・react-native-paper 4.9.2<br>
・moment 2.29.1<br>

<p>参考にしたサイト</a><br>
<a href="https://firebase.google.com/">Firebase公式</a><br>
<a href="https://qiita.com/Yametaro/items/af7dde38c6523dba110c">ワイ「なに！？型のズレを吸収できるやと！？」
</a>

<h1>（３）お知らせを配信する</h1>

<p>まずは、お知らせ配信について。firebase のデータベースサービスである firestoreを使います、webから直接データを書き込むことができるので便利です。下記はfirebaseのver.8の書き方になります、最新のver.9は大きく変わったのでご注意ください。
</p>
```js
// Firebase.js
import firebase from "firebase";
import "firebase/firestore";

if (!firebase.apps.length) {
  const firebaseConfig = {
    apiKey: "必要な値を入力してください"
    projectId: "必要な値を入力してください",
    appId: "必要な値を入力してください",
  };
  firebase.initializeApp(firebaseConfig);
}

export const getInfo = async () => {
  try {
    const snapshot = await firebase.firestore().collection("info").get();
    const info = snapshot.docs.map((doc) => ({
      ...doc.data(),
      id: doc.id,
    }));
    return info;
  } catch (err) {
    console.log(err);
  }
};
```
![firebase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635004/155f47a0-1b4c-fccd-88f9-ecc8c7323316.png)

<p>web上で直接配信したい内容を登録することができます。</p>

<h1>（４）配信されたお知らせを表示する</h1>
<p>ページ遷移でお知らせのページに来た時にisFocusedが発火し、getFirebaseItems関数が実行されます。INFORMATION_LISTに先ほどのfirestoreから取得したデータをセットします。</p>

```ts
import { getInfo } from "./Firebase";
import { useIsFocused } from "@react-navigation/native";

const [INFORMATION_LIST, setINFORMATION_LIST] = useState([]);
const isFocused = useIsFocused();

  useEffect(() => {
    getFirebaseItems();
  }, [isFocused]);

  const getFirebaseItems = async () => {
    const info = await getInfo();
    await setINFORMATION_LIST(info);
  };
```


<p>useEffectでlistに変数information（保存されているお知らせ一覧）をセットします。<br>
onPress関数はお知らせが表示されているCardをタップすると実行されます。そのお知らせがlist.includesで含まれるかを判定し、含まれていなければaddInformation関数で変数informationに[...value, value]で追加セットします。配列を均すflat(1)については参考サイトの<a href="https://qiita.com/Yametaro/items/af7dde38c6523dba110c">ワイ「なに！？型のズレを吸収できるやと！？」</a>を参照ください、面白いですよ！informationが変化するのでuseEffectが反応します。<br>
変数informationを端末に保存するには<a href="https://qiita.com/syeha/items/2b304693d870c5ab6b1a">Expoを利用したアプリでreact-native-async-storageを使う</a>を参考にしていただければと思います。</P>

```js
import { Card } from "react-native-paper";

const [information, setInformation] = useState([]);
const [list, setList] = useState([]);

  useEffect(() => {
    setList(information);
    const timer = setTimeout(() => {
      setLoading(false);
    }, 500);
    return () => clearTimeout(timer);
  }, [information]);

  const onPress = (value) => {
    if (list.includes(value.no) !== true) {
      addInformation(value.no);
  };

  const addInformation = (value) => {
    setInformation([...value, value].flat(1));
  };
```

<p>FlatListで展開するためのrenderInformationItemを作成します。react-native-paperのCardを利用すると簡単にカード表示ができます。。list.includes(item.no)で該当するitem.noがあればnull、該当するitem.noがなければ「未読」と表示させます</p>
```js

const renderInformationItem = ({ item }) => {
    return (
      <Card>
        <Card.Content>
          <View style={{ flexDirection: "row" }}>
            <Text>
              {item.name}
            </Text>
            {list.includes(item.no) === true ? null : (
              <Text>
                未読
              </Text>
            )}
          </View>
          <Text>
            {moment(item.date).format("YYYY年MM月DD日(ddd)")}
          </Text>
          <TouchableOpacity
            onPress={() => onPress(item)}
          >
            <Text>
              続きを読む
            </Text>
          </TouchableOpacity>
        </Card.Content>
      </Card>
    );
```

では、展開してみましょう。FlatListタグがとても使いやすく renderItem={}に先ほど作成した
renderInformationItemを設定することで展開してくれます。


```js
     <ScrollView>
       {INFORMATION_LIST.length !== 0 ? (
         <FlatList
           data={INFORMATION_LIST ?? []}
           renderItem={renderInformationItem}
           keyExtractor={(item) => item.no}
         />
        ) : (
        <Text>
          お知らせはありません
        </Text>
      )}
    </ScrollView>
```
<h1>（５）終わりに</h1>

<p>配信されたお知らせが未読かどうかを判定する方法はいろいろあるかと思います。個人識別ができるならばデータベースで未読かどうかをチェックするのかな。ひとつの方法として参考にしていただけると幸いです:relaxed:</p>