Angular + nxrxにRedux Toolkitを追加してみた覚書
意図 Action / Reducerなどの作成をまとめてできるcreateSlice関数が使いたかった。 また、手慣れた書き方ができるならそっちのほうが良さそうに感じたこともあります。 インストール ライブラリをそれぞ […]
広告ここから
広告ここまで
目次
意図
Action / Reducerなどの作成をまとめてできるcreateSlice
関数が使いたかった。
また、手慣れた書き方ができるならそっちのほうが良さそうに感じたこともあります。
インストール
ライブラリをそれぞれ追加します。
$ npm i @ngrx/store @reduxjs/toolkit
app.module.ts
にngrxのStoreModuleを登録する
まずはrootで登録します。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, StoreModule.forRoot({}, {})],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
createSlice
でActionやReducerを作る
ActionやReducerなどはRedux Toolkitで作ります。
Selectorだけngrx
の関数が入ります。
import { createSlice, CaseReducer } from '@reduxjs/toolkit'
import { createFeatureSelector } from '@ngrx/store'
export type CounterState = {
count: number
}
const counterSlice = createSlice<CounterState, {
increment: CaseReducer<CounterState, {
type: string
}>
}>({
name: 'counter',
initialState: {
count: 0
},
reducers: {
increment: state => {
state.count++
}
}
})
export const {
reducer: counterReducer,
actions: {
increment
},
name: counterFeatureKey
} = counterSlice
export const selectFeature = createFeatureSelector<ReturnType<typeof counterReducer>>(counterFeatureKey)
使いたいページのModuleでStoreを登録する
rootに登録しても良さそうなのですが、forFeature
を使えば使いたい部分のModuleにだけ登録できるみたいです。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { StoreModule } from '@ngrx/store';
import { Demo
RoutingModule } from './demo-routing.module';
import { HomeComponent } from './home/home.component';
import { counterFeatureKey, counterReducer } from '../stores/counter';
import { anotherFeatureKey, another
Reducer } from '../stores/another
';
@NgModule({
declarations: [
HomeComponent
],
imports: [
CommonModule,
Demo
RoutingModule,
StoreModule.forFeature(counterFeatureKey, counterReducer),
// 複数の場合
StoreModule.forFeature(anotherFeatureKey, anotherReducer)
]
})
export class DemoModule { }
Dispatch / Subscribeする
呼び出す時はstore.dispatch
、データのsubscribeがしたい場合はstore.select
を使います。
createSelector
の処理自体も事前定義しておいて良い気はしますが、未検証です。
import { Component, OnInit } from '@angular/core';
import { Store, createSelector } from '@ngrx/store'
import { selectFeature } from 'src/app/stores/counter/selector';
import { increment } from 'src/app/stores/counter/slice';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private readonly store: Store) { }
public counter$ = this.store.select(createSelector(selectFeature, state => state.count))
public increment() {
this.store.dispatch(increment())
}
}
非同期処理について
createAsyncThunk
やRTK Queryをそのまま使うのは、パッと調べた範囲では難しそうです。
@ngrx/effect
を使うか、非同期処理の結果だけStoreにいれるかなどを検討した方が、今の自分のレベルにはあってそうです。
参考
https://blog.lacolaco.net/2020/12/angular-using-ngrx-with-redux-toolkit/