Vuex Appをあらゆる場所で簡単に動かす方法
kahirokunn
Web Frontendの人
Vue, React, Angular全部書いてる
最近はqiitaサボってる
後はひたすら基礎勉してます
コアな実装もいうて面白く話せる自信がなかったので、ネタに走りました。(今日の朝1時から資料作り始めたなんて言えない😢
今回はあまりメンテしてませんが、book-managementという半年以上前の自分が書いたコードをサンプルにします。
このコードは何を血迷ったのか、Vuexの型定義で落ち込んでいた際にやってしまった、深夜のノリ的な奴です。
お付き合いいただけたらと思います。
ゴール
jestとかのmockを一切使わないであらゆる環境であらゆるコンポーネント(ページ含む)を動かす
今回の登場人物
- InversifyJS
- Vue・Vuex
- DIとかその辺の用語
- Storybookやテストの話がちょろっと
const initialState = (): State => ({
isOpen: false,
screenState: ScreenState.STANDBY,
})
const mutations: MutationTree<State> = {
[SuccessUpdateAction.type](state, action: SuccessUpdateAction) {
state.screenState = ScreenState.SEND_SUCCESS
},
[FailureSendAction.type](state, action: FailureSendAction) {
state.screenState = ScreenState.SEND_FAILED
},
[ToStandbyAction.type](state, action: ToStandbyAction) {
state.screenState = ScreenState.STANDBY
},
[OpenDialog.type](state, action: OpenDialog) {
state.isOpen = true
},
[CloseDialog.type](state, action: CloseDialog) {
state.isOpen = false
},
}
const actions: ActionTree<State, RootState> = {
async [UpdateProfileAction.type]({ commit }, action: UpdateProfileAction) {
try {
const user = await apiClient.post<User>('/user/update', action.user)
commit(new SuccessUpdateAction())
commit(new UpdatedUserProfileEvent(user))
} catch (e) {
commit(new FailureSendAction())
}
},
}
export default {
state: initialState,
mutations,
actions
}
これと似た感じに書く事が多いんじゃないかな
const actions: ActionTree<State, RootState> = {
async [UpdateProfileAction.type]({ commit }, action: UpdateProfileAction) {
try {
const user = await apiClient.post<User>('/user/update', action.user)
commit(new SuccessUpdateAction())
commit(new UpdatedUserProfileEvent(user))
} catch (e) {
commit(new FailureSendAction())
}
},
}
これ、動かすのにいちいち通信の事気にしないといけなくてめんどくさいですよね。
jestで場当たり的にモックするのも大変。
コードの依存はこんな感じ。
// users.test.js
import axios from 'axios';
import Users from './users';
jest.mock('axios');
test('should fetch users', () => {
const users = [{name: 'Bob'}];
const resp = {data: users};
axios.get.mockResolvedValue(resp);
// or you could use the following depending on your use case:
// axios.get.mockImplementation(() => Promise.resolve(resp))
return Users.all().then(data => expect(data).toEqual(users));
});
今回はこれ禁止
テストの時も
storybook上でも
通信の事気にしないで好きに使いたい!
vue test utilも
shallow mountだけじゃなく
気軽にmountしたい!
この手の要件はDIのおはこ
このfetch等のネットワークへの依存部分をStore Optionから外せば成功
これを
こう!!!
依存の話になると関数かclassがあると便利
export class ChangeUserProfileFormModule {
constructor(private readonly userApp: IUserApplicationService) { }
public state() { return initialState() }
get mutations(): MutationTree<State> {
return {
[SuccessUpdateAction.type](state, action: SuccessUpdateAction) {
state.screenState = ScreenState.SEND_SUCCESS
},
[FailureSendAction.type](state, action: FailureSendAction) {
state.screenState = ScreenState.SEND_FAILED
},
[ToStandbyAction.type](state, action: ToStandbyAction) {
state.screenState = ScreenState.STANDBY
},
[OpenDialog.type](state, action: OpenDialog) {
state.isOpen = true
},
[CloseDialog.type](state, action: CloseDialog) {
state.isOpen = false
},
}
}
get actions(): ActionTree<State, RootState> {
return {
async [UpdateProfileAction.type]({ commit }, action: UpdateProfileAction) {
try {
const user = await apiClient.post<User>('/user/update', action.user)
commit(new SuccessUpdateAction())
commit(new UpdatedUserProfileEvent(user))
} catch (e) {
commit(new FailureSendAction())
}
}
}
}
}
でもこんなコードは書きたくない。
DIコンテナが欲しい
new ChangeUserProfileFormModule(new UserApplicationService())
InversifyJSっていう
良さげなDIコンテナのライブラリがあった
こんな感じで依存に解決したいクラスとそれに必要なクラスを全部入れてgetすると依存解決済みのインスタンスをくれる
import { Container } from 'inversify'
const container = new Container()
container.bind(IAuthApplicationService).to(AuthApplicationService)
container.bind(ChangeUserProfileFormModule).to(ChangeUserProfileFormModule)
const store = createStore(container.get(ClassBasedStoreOption))
network依存切り離せたので
storeを全ての環境で動かす準備が整いました
storybookでも
browserでも
unit testでも
mockなしで簡単に動く
デモgif
zisuiもいける
DEMO
demoする余裕あれば
あまりメンテしてませんが、ここまでのサンプルコード良ければどうぞ
ネタなので真に受けないでください
ここまでやりましたが
ご静聴ありがとうございました
Vuex Appをあらゆる場所で簡単に動かす方法
By kahirokunn
Vuex Appをあらゆる場所で簡単に動かす方法
- 2,519