Twitterクローンを作ります #8 サイドメニューとログアウト

今回はメイン画面の左に表示するサイドメニューを作って行きます。


# サイドメニュー

まずはメニュー用のコンポーネントを作成します。

```vue:client/src/components/SideNav.vue
<template>
    <ul class="uk-iconnav uk-iconnav-vertical uk-padding">
        <li><router-link to="/" uk-icon="icon: home; ratio: 2" uk-tooltip="title: ホーム; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: search; ratio: 2" uk-tooltip="title: 検索; pos: right"></router-link></li>
        <li><router-link to="/about" uk-icon="icon: bell; ratio: 2" uk-tooltip="title: 通知; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: mail; ratio: 2" uk-tooltip="title: メッセージ; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: user; ratio: 2" uk-tooltip="title: プロフィール; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: sign-out; ratio: 2" uk-tooltip="title: ログアウト; pos: right"></router-link></li>
    </ul>
</template>
```

次に、デフォルトのレイアウトの左端に先程作成したSideNavを表示するようにします。

```vue:client/src/components/layouts/DefaultLayout.vue
<template>
    <div class="uk-grid">
        <div class="uk-width-auto">
            <side-nav></side-nav>
        </div>
        <div class="uk-width-expand">
            <router-view></router-view>
        </div>
    </div>
</template>

<script>
import SideNav from '@/components/SideNav.vue';

export default {
  components: {
    SideNav
  }
}
</script>

```

![スクリーンショット 2022-03-13 1.28.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/ff98ca33-c1f7-934e-73e7-7fd0cece5210.png)

いい感じにメニューが表示されましたね。
ついでにログアウト機能も作成してしまいましょう。

# ログアウト

まずはログアウトAPIを実装していきます。

```python:server/apis/login.py
...


@app.route('/api/logout', methods=['POST'])
def logout():
    session['user'] = None
    return "", 204
```

画面側は、まずstoreを以下のように修正します。ログアウトAPI呼び出し -> データのクリア -> ログイン画面へ遷移、といった内容になっています。

```javascript:client/store/index.js
...

  actions: {
    registerUser ({ commit }, user) {
      axios.post('/api/users', user).then(resp => {
        commit('setUserLoggedIn', resp.data);
        router.push('/');
      })
      .catch(error => {
        UIkit.notification(error.response.data.error.message, {status: 'danger'});
      });
    },
    login ({ commit }, credential) {
      axios.post('/api/login', credential).then(resp => {
        commit('setUserLoggedIn', resp.data);
        router.push('/');
      })
      .catch(error => {
        UIkit.notification(error.response.data.error.message, {status: 'danger'});
      });
    },
    logout ({ commit }) {
      axios.post('/api/logout').then(() => {
        commit('setUserLoggedIn', undefined);
        router.push('/login');
      })
      .catch(error => {
        UIkit.notification(error.response.data.error.message, {status: 'danger'});
      });
    }
  },
...

```

SideNavを以下のように修正します。

```vue:client/src/components/SideNav.vue
<template>
    <ul class="uk-iconnav uk-iconnav-vertical uk-padding">
        <li><router-link to="/" uk-icon="icon: home; ratio: 2" uk-tooltip="title: ホーム; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: search; ratio: 2" uk-tooltip="title: 検索; pos: right"></router-link></li>
        <li><router-link to="/about" uk-icon="icon: bell; ratio: 2" uk-tooltip="title: 通知; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: mail; ratio: 2" uk-tooltip="title: メッセージ; pos: right"></router-link></li>
        <li><router-link to="/" uk-icon="icon: user; ratio: 2" uk-tooltip="title: プロフィール; pos: right"></router-link></li>
        <li><span @click="logout" uk-icon="icon: sign-out; ratio: 2" uk-tooltip="title: ログアウト; pos: right"></span></li>
    </ul>
</template>

<script>
import { useStore } from 'vuex';

export default {
    setup() {
        const store = useStore();

        const logout = () => {
            store.dispatch("logout");
        };

        return {
            logout
        };
    },
}
</script>

```

これでログアウト機能も実装できました。