2018-04-19

Nuxtでrouteに応じてVuex Storeをmodule分割する方法

まとめ

  • Nuxt は route に応じて自動で Vuex Store を module 分割できるが、あえて手動で registerModule することもできる
  • module 分割の際に大事なのは
    • namespaced 設定
    • state を function に
    • registerModule はすでに存在する module を上書きしてしまう(壊れる)
  • Store は SSR での扱いに注意が必要。不要なら beforeMount() 以降のタイミングで初期化することでサーバサイドでは無視されるようにすることができる。

Vuex Storeのmodule分割の基本

cf. モジュール · Vuex

基本的な Vuex Store の構造は

state: {
},
mutations: {
},
actions: {
}

となるが、これを以下のようにする。

{
  modules: {
    name: {
      state: {
      },
      mutations: {
      },
      actions: {
      }
    },
    name: {
      state: {
      },
      mutations: {
      },
      actions: {
      }
    }
  }
}

Nuxt.js では store/ 以下に page に対応する module 構造を置いてあげれば自動的に module として登録される。便利。

routeに同期させて同一構造のmoduleを手動でregisterする

手動 register

module 構造の Store を作る方法は上の構造の object をそのまま new Vuex.Store() に突っ込んでもよいのだが、動的に組むには store.registerModule(NAME, OBJECT) してあげるとよい。

Nuxt の場合は特に何の設定もしなくても各 component から this.$store で Vuex Store へアクセスできるので、

this.$store.registerModule(NAME, OBJECT)

になる。

同一構造の module を動的 register する際の注意点

  1. namespaced: true を設定
  2. state は function
  3. module を registerModule するタイミングで state が消える
  4. Vue の SSR が beforeCreate(), created() までしか Lifecycle Hook を利用できないので、beforeMount() 以降で初期化すると client side だけに集中できる

created() で registerModule 以外の $store 操作を行なっている場合は module 生成 1 については同一構造の state が複数あるとどれに対してアクセスしているのかを明示しつつそれぞれの影響範囲が閉じている必要がある。そのための namespaced.

2 については Vue component の data と同じ。インスタンスが複数登場する場合は plain object を使ってしまうと state がみんな同じになってしまう。

3 については分かってしまえばその通りなんだけど、route を手動で書かなくても自動的に設定してくれる Nuxt 環境では注意しないといけない点。

実際にどう対処するか、以下のコードをサンプルとして挙げておく。module name を route name と同一にすると仮定した場合はこのように意図せぬ Store の破壊を防ぎつつ構築していくとよい。

if ( typeof this.$store.state[this.$route.name] == 'undefined' ) {
  this.$store.registerModule(
    this.$route.name,
    {
      namespaced: true,
      state() {
        return {
        }
      },
      mutations: {
      },
      actions: {
      }
    }
  )
}

4 はしばらくハマった。Nuxt で Universal アプリを書くことにした場合、Vue の SSR の知識なしに始めると変なところでハマる可能性があるので注意が必要。

Singleton な Store を Universal アプリで利用するには root component が初期化される前に acyncData で行うのがスジらしい。

今回は Nuxt が最初から用意してくれている Page component に hook して registerModule しようという考えだったので、created() の後に registerModule することで SSR 時には無視されるようにした。

cf. データのプリフェッチと状態 · GitBook

※ なお、困ったことに vue-devtool では Store が破壊されたことは分からない。そこまで中の状態を細かく見ていないようだ。少なくとも v4.1.1 の段階では分からなかった。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm