質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.97%

Nuxt.jsビギナーズガイドで発生した、Cannot read property 'id' of nullエラーについて

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 211

toshihirokato

score 12

前提・実現したいこと

Nuxt.jsビギナーズガイドのnuxt-blog-serviceを作成中で、
ユーザー機能を実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

TypeError: Cannot read property 'id' of null

該当のソースコード

<template>
  <div>
    <el-row v-if="user">
      <el-col :span="6">
        <el-card class="text-center" style="margin-right: 16px;">
          <div>
            <img
             src="https://placehold.it/150x150"
             style="width: 100%;margin-bottom: 16px;border-radius: 2px;"
             alt=""
             />
          </div>
          <h2>
          </h2>
        </el-card>
      </el-col>
      <el-col :span="18">
        <el-card>
          <div slot="header" class="clearfix">
            <span>{{user.id}} さんの投稿</span>
          </div>
          <el-table
            :data="userPosts"
            style="width: 100%"
            class="table"
          >
            <el-table-column
              prop="title"
              label="タイトル"
            />
            <el-table-column
              prop="created_at"
              label="投稿日時"
              width="160"
            />
          </el-table>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import moment from '~/plugins/moment'
import { mapGetters } from 'vuex'

export default {
  async asyncData({ store, route, error }){
    const { id } = route.params
    try {
      await store.dispatch('users/fetchUser', { id })
    } catch(e) {
      error({ statusCode: 404 })
    }
  },
  computed: {
    userPosts(){
      return Object.entries(this.user.posts).map(([id, post]) => {
        post.created_at = moment(post.created_at).format('YYYY/MM/DD HH:mm:ss')
        return { id, ...post }
      })
    },
    user(){
      const user = this.users.find(u => u.id === this.$route.params.id)
      if (!user) return null
      return Object.assign({ posts: [] }, user)
    },
    ...mapGetters('users', ['users'])
  }
}
</script>

該当のソースコード

import moment from '~/plugins/moment'

export const state = () => ({
  isLoggedIn: false,
  user: null
})

export const getters = {
  isLoggedIn: state => state.isLoggedIn,
  user: state =>
    (state.user ? Object.assign({ likes: [] }, state.user) :null)
}

export const mutations = {
  setUser(state, { user }) {
    if (user.id.match(/_|@|\./)) {
      throw new TypeError('invalid username')
    }
    state.user = user
    state.isLoggedIn = true
  },
  updateUser(state, { user }) {
    state.user = user
  }
}

export const actions = {
  async login({ commit }, { id }) {
    if (id.match(/_|@|\./)) {
      throw new TypeError('invalid username')
    }
    const user = await this.$axios.$get(`/users/${id}.json`)
    console.log(user)
    if (!user.id) throw new Error('Invalid user')
    commit('setUser', { user })
  },
  async register({ commit }, { id }) {
    const payload = {}
    payload[id] = { id }
    await this.$axios.$patch(`/users.json`, payload)
    const user = await this.$axios.$get(`/users/${id}.json`)
    if (!user.id) throw new Error('Invalid user')
    commit('setUser', { user })
  },
  async addLikeLogToUser({ commit }, { user, post }) {
    user.likes.push({
      created_at: moment().format(),
      user_id: user.id,
      post_id: post.id
    })
    const newUser = await this.$axios.$put(`/users/${user.id}.json`, user)
    commit('updateUser', { user: newUser })
  },
  async removeLikeLogToUser({ commit }, { user, post }) {
    user.likes = post.likes.filter(like => like.user_id !== user.id) || []
    const newUser = await this.$axios.$put(`/users/${user.id}.json`, user)
    commit('updateUser', { user: newUser })
  }
}

 

該当のソースコード

import moment from '~/plugins/moment'

export const state = () => ({
  posts: []
})

export const getters = {
  posts: state =>
    state.posts.map(post => Object.assign({ likes: [] }, post))
}

export const mutations = {
  addPost(state, { post }) {
    state.posts.push(post)
  },
  updatePost(state, { post }) {
    state.posts = state.posts.map((p) => (p.id === post.id ? post: p))
  },
  clearPosts(state) {
    state.posts = []
  }
}

export const actions = {
  async fetchPost({ commit }, { id }) {
    const post = await this.$axios.$get(`/posts/${id}.json`)
    commit('addPost', { post: { ...post, id } })
  },
  async fetchPosts({ commit }) {
    const posts = await this.$axios.$get(`/posts.json`)
    commit('clearPosts')
    Object.entries(posts || [])
      .reverse()
      .forEach(([id, content]) =>
        commit('addPost', {
          post: {
            id,
            ...content
          }
        })
      )
  },
  async publishPost({ commit }, { payload }) {
    const user = await this.$axios.$get(`/users/${payload.user.id}.json`)
    const created_at = moment().format()
    payload = {
      created_at,
      ...payload
    }
    const post_id = (await this.$axios.$get('/posts.json', payload)).name
    const post = { id: post_id, ...payload, created_at }
    const putData = { id: post_id, ...payload, created_at }
    delete putData.user
    await this.$axios.$put(`/users/${user.id}/posts.json`, [
      ...(user.posts || []),
      putData
    ])
    commit('addPost', { post })
  },
  async addLikeToPost({ commit }, { user, post }) {
    post.likes.push({
      created_at: moment().format(),
      user_id: user.id,
      post_id: post.id
    })
    const newPost = await this.$axios.$put(`/posts/${post.id}.json`, post)
    commit('updatePost', { post: newPost })
  },
  async removeLikeToPost({ commit }, { user, post }) {
    post.likes = post.likes.filter(like => like.user_id !== user.id) || []
    const newPost = await this.$axios.$get(`/posts/${post.id}.json`, post)
    commit('updatePost', { post: newPost })
  }
}

 

該当のソースコード

export const state = () => ({
  users: []
})

export const getters = {
  users: state => state.users
}

export const mutations = {
  addUser(state, { user }) {
    state.users.push(user)
  },
  addUserPost(state, { user, post }) {
    state.userPosts[user.id].push(post)
  },
  clearUserPosts(state, { user }) {
    state.userPosts[user.id] = []
  }
}

export const actions = {
  async fetchUser({ commit }, { id }) {
    const user = await this.$axios.$get(`/users/${id}.json`)
    commit('addUser', { user })
  },
  async addLikeLogToUser({ commit }, { user, post }) {
    post.likes.push({
      created_at: moment().format(),
      user_id: user.id,
      post_id: post.id
    })
    const newPost = await this.$axios.$get(`/posts/${post.id}.json`, post)
    commit('updatePost', { post: newPost })
  },
  async removeLikeLogToUser({ commit }, { user, post }) {
    post.likes = post.likes.filter(like => like.user_id !== user.id) || []
    const newPost = await this.$axios.$put(`/posts/${post.id}.json`, post)
    commit('updatePost', { post: newPost })
  }
}

 

試したこと

yarn run lint --fix等のツールでエラー解析したが、原因を見つけることができませんでした。

補足情報(FW/ツールのバージョンなど)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • y_waiwai

    2019/10/21 08:01

    先の質問となにか変わってるんでしょうか

    キャンセル

  • ryuii

    2019/10/21 10:46

    Storeは正しく実装されていますか?usersとpostsあたりのidがうまく作られていないようです。

    キャンセル

  • toshihirokato

    2019/10/23 14:37

    ご指摘いただきありがとうございます!
    storeディレクトリ内のプロジェクトを追記させていただきましたので、お手隙の際に見ていただけると幸いです。
    よろしくお願いいたします。

    キャンセル

回答 2

check解決した方法

+1

app/store/index.jsやusers.js内の(/users/${id}.json)が(/users/#{id}.json)となっていましたので、(/users/${id}.json)に書き直したところ、上記のエラーを解決することができました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

以下URLに該当の書籍のソースコードがあるようですので、こちらを参照したほうが解決が早そうです。
GitHub: nuxt-beginners-guide

エラーメッセージがどこで発生しているかというところがわかると原因がわかりやすいです。

例えば、ログイン画面でログインするときにFirebaseのデータベースにユーザーが存在しないときに、
質問者様と同じエラーが発生します。
その場合は、try ~ catch文のcatchにエラーが発生した場合の処理を書いて、エラー内容をポップアップ表示したり、処理が止まったりすることを未然に防いでいます。

あと、users.jsのactionsの
axiosの参照(get)・登録(post)・更新(put)の部分が異なるようです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/24 16:12

    ご回答いただきありがとうございます!
    users.jsファイル内のactionsのaxiosのget, post, putを書籍のソースコードと全く同じにしたのですが、それでも同じエラー文が表示され、解決できないかったので、ryuii様の仰る通りにtry-catch構文を加えてエラー箇所を絞りたいと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.97%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る