diff --git a/angular.json b/angular.json
index 72c8107..326b9d1 100644
--- a/angular.json
+++ b/angular.json
@@ -190,6 +190,75 @@
"builder": "@angular-devkit/build-angular:extract-i18n"
}
}
+ },
+ "angular-redux-auto-dispatch-demo": {
+ "projectType": "application",
+ "schematics": {},
+ "root": "projects/angular-redux-auto-dispatch-demo",
+ "sourceRoot": "projects/angular-redux-auto-dispatch-demo/src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:application",
+ "options": {
+ "outputPath": "dist/angular-redux-auto-dispatch-demo",
+ "index": "projects/angular-redux-auto-dispatch-demo/src/index.html",
+ "browser": "projects/angular-redux-auto-dispatch-demo/src/main.ts",
+ "polyfills": [
+ "zone.js"
+ ],
+ "tsConfig": "projects/angular-redux-auto-dispatch-demo/tsconfig.app.json",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "projects/angular-redux-auto-dispatch-demo/public"
+ }
+ ],
+ "styles": [
+ "projects/angular-redux-auto-dispatch-demo/src/styles.css"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kB",
+ "maximumError": "1MB"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "4kB",
+ "maximumError": "8kB"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "angular-redux-auto-dispatch-demo:build:production"
+ },
+ "development": {
+ "buildTarget": "angular-redux-auto-dispatch-demo:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n"
+ }
+ }
}
}
}
diff --git a/projects/angular-redux-auto-dispatch-demo/public/favicon.ico b/projects/angular-redux-auto-dispatch-demo/public/favicon.ico
new file mode 100644
index 0000000..57614f9
Binary files /dev/null and b/projects/angular-redux-auto-dispatch-demo/public/favicon.ico differ
diff --git a/projects/angular-redux-auto-dispatch-demo/src/app/app.component.ts b/projects/angular-redux-auto-dispatch-demo/src/app/app.component.ts
new file mode 100644
index 0000000..403be28
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/app/app.component.ts
@@ -0,0 +1,24 @@
+import { Component, effect } from '@angular/core';
+import { injectSelector, injectDispatch } from '@reduxjs/angular-redux';
+import { decrement, increment } from './store/counter-slice';
+import { RootState } from './store';
+
+@Component({
+ selector: 'app-root',
+ standalone: true,
+ template: `
+
+ {{ count() }}
+
+ `,
+})
+export class AppComponent {
+ count = injectSelector((state: RootState) => state.counter.value);
+ dispatch = injectDispatch();
+ increment = increment;
+ decrement = decrement;
+
+ _auto_increment = effect(() => {
+ this.dispatch(increment());
+ });
+}
diff --git a/projects/angular-redux-auto-dispatch-demo/src/app/app.config.ts b/projects/angular-redux-auto-dispatch-demo/src/app/app.config.ts
new file mode 100644
index 0000000..8f1092f
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/app/app.config.ts
@@ -0,0 +1,10 @@
+import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
+import { provideRedux } from '@reduxjs/angular-redux';
+import { store } from './store';
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideZoneChangeDetection({ eventCoalescing: true }),
+ provideRedux({ store }),
+ ],
+};
diff --git a/projects/angular-redux-auto-dispatch-demo/src/app/store/counter-slice.ts b/projects/angular-redux-auto-dispatch-demo/src/app/store/counter-slice.ts
new file mode 100644
index 0000000..6f65718
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/app/store/counter-slice.ts
@@ -0,0 +1,35 @@
+import { createSlice } from '@reduxjs/toolkit';
+import type { PayloadAction } from '@reduxjs/toolkit';
+
+export interface CounterState {
+ value: number;
+}
+
+const initialState: CounterState = {
+ value: 0,
+};
+
+export const counterSlice = createSlice({
+ name: 'counter',
+ initialState,
+ reducers: {
+ increment: (state) => {
+ // Redux Toolkit allows us to write "mutating" logic in reducers. It
+ // doesn't actually mutate the state because it uses the Immer library,
+ // which detects changes to a "draft state" and produces a brand new
+ // immutable state based off those changes
+ state.value += 1;
+ },
+ decrement: (state) => {
+ state.value -= 1;
+ },
+ incrementByAmount: (state, action: PayloadAction) => {
+ state.value += action.payload;
+ },
+ },
+});
+
+// Action creators are generated for each case reducer function
+export const { increment, decrement, incrementByAmount } = counterSlice.actions;
+
+export default counterSlice.reducer;
diff --git a/projects/angular-redux-auto-dispatch-demo/src/app/store/index.ts b/projects/angular-redux-auto-dispatch-demo/src/app/store/index.ts
new file mode 100644
index 0000000..0e410ac
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/app/store/index.ts
@@ -0,0 +1,13 @@
+import { configureStore } from '@reduxjs/toolkit';
+import counterReducer from './counter-slice';
+
+export const store = configureStore({
+ reducer: {
+ counter: counterReducer,
+ },
+});
+
+// Infer the `RootState` and `AppDispatch` types from the store itself
+export type RootState = ReturnType;
+// Inferred type: {counter: CounterState}
+export type AppDispatch = typeof store.dispatch;
diff --git a/projects/angular-redux-auto-dispatch-demo/src/index.html b/projects/angular-redux-auto-dispatch-demo/src/index.html
new file mode 100644
index 0000000..e0cbc09
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ AngularReduxDemo
+
+
+
+
+
+
+
+
diff --git a/projects/angular-redux-auto-dispatch-demo/src/main.ts b/projects/angular-redux-auto-dispatch-demo/src/main.ts
new file mode 100644
index 0000000..8882c45
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/main.ts
@@ -0,0 +1,7 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { appConfig } from './app/app.config';
+import { AppComponent } from './app/app.component';
+
+bootstrapApplication(AppComponent, appConfig).catch((err) =>
+ console.error(err),
+);
diff --git a/projects/angular-redux-auto-dispatch-demo/src/styles.css b/projects/angular-redux-auto-dispatch-demo/src/styles.css
new file mode 100644
index 0000000..90d4ee0
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/src/styles.css
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/projects/angular-redux-auto-dispatch-demo/tsconfig.app.json b/projects/angular-redux-auto-dispatch-demo/tsconfig.app.json
new file mode 100644
index 0000000..e40712b
--- /dev/null
+++ b/projects/angular-redux-auto-dispatch-demo/tsconfig.app.json
@@ -0,0 +1,15 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../out-tsc/app",
+ "types": []
+ },
+ "files": [
+ "src/main.ts"
+ ],
+ "include": [
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/projects/angular-redux/src/lib/inject-selector.ts b/projects/angular-redux/src/lib/inject-selector.ts
index a5c3603..d84f4ae 100644
--- a/projects/angular-redux/src/lib/inject-selector.ts
+++ b/projects/angular-redux/src/lib/inject-selector.ts
@@ -91,13 +91,12 @@ export function createSelectorInjection(): InjectSelector {
const { store, subscription } = reduxContext;
- const selectedState = linkedSignal(() => selector(store.getState()));
+ const selectedState = linkedSignal(() => selector(store.getState()), {
+ equal: equalityFn,
+ });
const unsubscribe = subscription.addNestedSub(() => {
const data = selector(store.getState());
- if (equalityFn(selectedState(), data)) {
- return;
- }
selectedState.set(data);
});