AngularJavaScript

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 { DemoRoutingModule } from './demo-routing.module';
import { HomeComponent } from './home/home.component';

import { counterFeatureKey, counterReducer } from '../stores/counter';
import { anotherFeatureKey, anotherReducer } from '../stores/another';


@NgModule({
  declarations: [
    HomeComponent
  ],
  imports: [
    CommonModule,
    DemoRoutingModule,
    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/

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts