[React] 「投稿がありません」コメント描画のロジックでハマった話

#前提
- React.js
- データベースはFirestore(Firebaseのcloud datebase)
- 投稿記事のvalueにFirebase Authenticationのuidをアップして連携可能にしている

# ハマったこと
現在SNSアプリの仕組みを実装している中、
投稿がない場合、「投稿がありません」と1文を出そうと思っていたところ、
下記コードのように配列でループで表示いるため、リスト分「投稿がありません」と表示されてしまう。
このままだとログイン(auth)投稿者以外の記事分、表示されてしまう。

いや〜マジで困った。

# やりたいこと
authユーザーの記事のみ表示　← これのみならすでに可能
　　　　　　　　　　　　かつ
もし記事がなかったら「投稿がありません」の1文を1個のみ表示

```jsx:問題の箇所抽出
{list.map(item => (
    <React.Fragment key={item.docId + String(new Date())}>
        {authId === item.authId ? (
            <div>{item.msg}</div>
        ) : (
            {/* ループの中に入っているためリスト分表示されてしまう */}
            <div>
                投稿がありません
            </div>
        )}
    </React.Fragment>
))}
```

# 解決方法
以下の方法で無事解決できました。

## うまくいった方法
処理を分けて書けばよかった

js側・・・投稿記事を抽出するロジックを書いて結果を出しておく
- 事前に配列を`filter`して、表示すべき分だけに絞り込んでおく
- 配列の`length`を取得

jsx側・・・表示のみにする
- 1つもなければ(lengthが0なら)「ありませんでした」メッセージを表示
- `filter`後の配列をmapして出力

### 解決に至った記事
[【JavaScript入門】filterで配列のデータを抽出する方法](https://www.sejuku.net/blog/21887)

```jsx:解決箇所抽出
// js側で抽出
    // auth userの投稿記事のみ抽出
    const result = list.filter((e) => {
        return e.authId === authId;
    });
    console.log(result);
    const length = result.length;
    console.log(length);

{/* jsx側で表示 */}
<div className="post-list user-post-list">
{length !== 0 ? (
    <React.Fragment>
        {result.map(item => (
            <div key={item.docId + String(new Date())}>
                <div className="auth-inner-post-list">
                    <div className="auth-inner-post-text">
                        <div className="post-msg">{item.msg}</div>
                        <span className="delete"  onClick={() => handleDelete(item.docId)}>&gt; Delete...</span>
                    </div>
                </div>
            </div>
        ))}
    </React.Fragment>
) : (
    <div className="no-user-posts">まだ記事が投稿されていません</div>
)}
</div>
```

```jsx:コード全文
import React from 'react';
import { Link } from 'react-router-dom';
import firebase, { db } from '../../Firebase';
import SignOut from '../FirebaseAuthHook/SignOut';
import { useCollectionData } from "react-firebase-hooks/firestore";
import BackTopIcon from '../../assets/img/backtop.png';
import UserIcon from '../../assets/img/user.png';
import styled from 'styled-components';

const BackTopStyle = styled.img`
  width: 50px;
  top: 25px;
  left: 25px;
  position: fixed;
  zIndex: 11,
`;

const Index = () => {
    // Firebese Auth uid, email取得
    const user = firebase.auth().currentUser;
    let authId;
    let name;
    let photoURL;
    if (user !== null) {
        user.providerData.forEach(() => {
            authId = user.uid;
            name = user.displayName;
            photoURL = user.photoURL;
        });
    }

    // Render
    const [ list, loading, error ] = useCollectionData(db.collection('posts').orderBy('createdAt', 'desc'), { idField: 'docId' });
    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error...</div>;
     
    // auth userの投稿記事のみ抽出
    const result = list.filter((e) => {
        return e.authId === authId;
    });
    console.log(result);
    const length = result.length;
    console.log(length);
    

    // Delete
    const handleDelete = (uid) => {
        if (window.confirm('削除しますか？')) {
            db.collection('posts').doc(uid).delete();
        }
    }
        
    return(
        <React.Fragment>
            <SignOut />
            <Link to="/"><BackTopStyle src={ BackTopIcon } alt="Topに戻る"/></Link>

            <div className="user-wrapper">
                <div className="user">
                    {photoURL ? (
                        <img src={ photoURL } className="auth-user-icon" alt="User Thumbnail" />
                    ) : (
                        <img src={ UserIcon } className="auth-user-icon" alt="Firebase Thumbnail" />
                    )}
                    <div className="user-datail">
                        {name ? (
                            <div className="user-name">{name}</div>
                        ) : (
                            <div className="user-name">Firebaseユーザー</div>
                        )}
                    </div>
                </div>

                <div className="post-list user-post-list">
                {length !== 0 ? (
                    <React.Fragment>
                        {result.map(item => (
                            <div key={item.docId + String(new Date())}>
                                <div className="auth-inner-post-list">
                                    <div className="auth-inner-post-text">
                                        <div className="post-msg">{item.msg}</div>
                                        <span className="delete"  onClick={() => handleDelete(item.docId)}>&gt; Delete...</span>
                                    </div>
                                </div>
                            </div>
                        ))}
                    </React.Fragment>
                ) : (
                    <div className="no-user-posts">まだ記事が投稿されていません</div>
                )}
                </div>
            </div>
        </React.Fragment>
    );
}

export default Index;
```

# 今回のことで学んだこと
分かってみると実に単純なことでした。
今後はView側で全て処理しようとせずにJS側でロジックを組むクセづけが必要だと感じました。
またフレームワークを使っていても素のJSのメソッドがかなり重要だと実感しています。