Skip to content

Commit

Permalink
V3.0 (#120)
Browse files Browse the repository at this point in the history
* Dependency Injection Improvements (#79)

* Dependency Injection Improvements

Updated API to fit better with Angular 2 DI.

The main change here is to delay configuring the
redux store until after the app has bootstrapped.
So instead of doing:

```typescript
import { provider } from 'ng2-redux';

bootstrap(App, [
  provider(configureStore()) ]);
```

We instead do:

```typescript
import { NgRedux } from 'ng2-redux';

bootstrap(App, [ NgRedux ]);

@component({
  // ...
})
class App {
  constructor(private ngRedux: NgRedux) {
    ngRedux.attach(configureStore());
  }
}
```

This is desirable for two reasons:

1. We can now inject angular services into NgRedux
itself
2. We can now inject angular services into redux
middleware and store enhancers.

(1) is needed to resolve the issue with redux
dev tools store updates happening outside the angular
zone.  We need to be able to do an `applicationRef.tick()`
on state update or the Angular UI doesn't respond to
dev tool actions.  Handling it internally this way is
preferable to making the end user remember to hook
it up manually.

(2) is a major feature that is currently impossible
in the old architecture, since previously the middleware
needed to be applied to the store before the Angular DI
was bootstrapped.

I think this approach is much more in line with how
people expect Angular 2 DI to function, and resolves
a number of other thorny init problems.

However it does represent an API change, and thus
will require a major version bump if adopted.

Also in this commit:
- some minor code cleanup
- switch to the more size-efficient rxjs import pattern
- marked the `select` api as deprecated.

* Added DI-injected middleware example with new DI strategy

Also added redux-logger to the example app as an example of using vanilla middlewares from the redux ecosystem.

* Added unit test for double store configuration error.

* Added test for devtools update mechanism.

* chore(*): Added linting with tslint, hooked it into CI (#84)

* feat(decorators): select, dispatch, dispatchAll

* chore(decorators): Move decorators (#91)

* Move decorators to own folder
* Create spec file for each decorator
* Rename dispatchAll.ts -> dispatch-all.ts
* Remove decorator spec from ngredux spec

* chore(ngRedux): Change lodash imports (#92)

* Instead of importing all of lodash, only import methods we need

* docs(decorators): updated README.md

* fix(@dispatch/All): arguments being passed as expected

* chore(specs): improved decorator interface test suite (#95)

* More v3 docs

- Changelog details
- Better DI action-creator example showing how `redux-thunk` is redundant in Angular 2.
- Demonstrate `redux-logger` and `redux-localstorage` as community-provided middleware and enhancer in example app.

Got rid of redux-thunk.

* Fix linter error upon rebase from master

* Resolve rebase conflict resolution error

* Rebased from master to consume recent v2.x fixes.

* Add missing doc updates.

* typo fix

* Prepare for 3.0 release.

Removes the `@dispatch` and `@dispatchAll` decorators since they are still experimental.

* v3.0 prep

* Remove `@dispatch` and `@dispatchAll` ref from docs
* Add Cosmin as contributer
  • Loading branch information
SethDavenport authored and e-schultz committed Jun 10, 2016
1 parent 1519b9a commit 51bd0a2
Show file tree
Hide file tree
Showing 27 changed files with 943 additions and 483 deletions.
192 changes: 147 additions & 45 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,163 @@
# 3.0.0

### Features

#### Select Decorator
This release introduces the new decorator interface. You can now use
`@select` to create an observable from a slice of store state.

See 'the select pattern' in [README.md](README.md#the-select-pattern)
for a complete description of how to use this new decorator.

#### Simpler Redux DevTools Integration

You no longer need to manually subscribe and `ApplicationRef.tick()`
for Redux DevTools to work; we do this automatically for you.

### Breaking Changes

#### Bootstrapping

We've changed how bootstrapping Ng2-Redux works. The `provider`
function has gone away in favour of making NgRedux a first-class
`@Injectable`.

You now configure your store in the constructor of your top-level
app component instead of prior to bootstrapping. This allows the
store to be configured with middleware and enhancers that rely on
Angular 2 services, which previously was unnecessarily difficult.

##### Old way:

**bootstrap.ts:**
```typescript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { createStore, applyMiddleware, compose } from 'redux';
import { NgRedux } from 'ng2-redux';
const createLogger = require('redux-logger');
const persistState = require('redux-localstorage');
import { rootReducer } from './reducers';
import { App } from './app';

// Confusing and hard to use with dependency injection.
const middleware = [ createLogger() ];
const enhancers = [ persistState('counter', { key: 'example-app' }) ];
const store = compose(
applyMiddleware(middleware),
...enhancers)
(createStore)(rootReducer);

bootstrap(App, [ provide(store) ])
```

**app.ts**
```typescript
import { Component } from '@angular/core';
import { NgRedux } from 'ng2-redux';

@Component({
// ...
})
export class App {
constructor(private ngRedux: NgRedux) {}
}
```

##### New way:

**bootstrap.ts:**
```typescript
import { bootstrap } from '@angular/platform-browser-dynamic';
import { NgRedux } from 'ng2-redux';
import { App } from './app';

bootstrap(App, [ Ng2Redux ]);
```

**app.ts**
```typescript
import { Component } from '@angular/core';
import { NgRedux } from 'ng2-redux';
import { reduxLogger } from 'redux-logger';
import { initialState, rootReducer } from './reducers';

@Component({
// ...
})
export class App {
constructor(private ngRedux: NgRedux) {
const middleware = [ reduxLogger ];
const enhancers = [ persistState('counter', { key: 'example-app' }) ];

// Easier to understand, and can use middleware or enhancers from DI.
ngRedux.configureStore(rootReducer, initialState, middleware, enhancers);
}
}
```

#### Example App Updates

The example app has been updated to use `@select` and a
DI-aware action creator service (`counter-actions.ts`). It now also
shows examples of using middleware and enhancers from the Redux
community: `redux-logger` and `redux-localstorage`.

# 2.2.2

### Features

* **type definitions**:
* **Type definitions**:
* Ported to typescript
* Supports typed stores / reducers
* Uses offical Redux type definitions
* **Type Injectable**:
* Able to inject `NgRedux` into your component by type, and not need `@Inject('ngRedux')`
* `@Inject('ngRedux')` still works

```ts
import { NgRedux } from 'ng2-redux';
// ...
export class MyComponent {
constructor(private ngRedux: NgRedux) {
}
}
```

```typescript
import { NgRedux } from 'ng2-redux';
// ...
export class MyComponent {
constructor(private ngRedux: NgRedux) {}
}
```
* **State as Observable**: Ability to expose parts of your state as an observable.
```ts
select<S>(selector: string | number | symbol | ((state: RootState) => S), comparer?: (x: any, y: any) => boolean): Observable<S>;

```typescript
select<S>(selector: string | number | symbol | ((state: RootState) => S), comparer?: (x: any, y: any) => boolean): Observable<S>;
wrapActionCreators: (actions: any) => (dispatch: Redux.Dispatch<any>) => Redux.ActionCreator<{}> | Redux.ActionCreatorsMapObject;
```

Example use:

```js
import { NgRedux } from 'ng2-redux';
// ...
export class MyComponent implements OnInit {
countByKey$: Observable<number>;
countByFunc$: Observable<number>;
constructor(private ngRedux: NgRedux) {
}
ngOnInit() {
this.countByKey$ = this.ngRedux.select('count');
this.countByFunc$ = this.ngRedux.select(state=>state.count);
}
}
```

Also have the ability to provide a custom compare function.

```js
import { is, Map } from 'immutable';
import { NgRedux } from 'ng2-redux';
// ...
export class MyComponent implements OnInit {
```

Example use:

```typescript
import { NgRedux } from 'ng2-redux';
// ...
export class MyComponent implements OnInit {
countByKey$: Observable<number>;
countByFunc$: Observable<number>;

constructor(private ngRedux: NgRedux) {
this.countByKey$ = this.ngRedux.select('count');
this.countByFunc$ = this.ngRedux.select(state=>state.count);
}
}
```

Also have the ability to provide a custom compare function.

```typescript
import { is, Map } from 'immutable';
import { NgRedux } from 'ng2-redux';

// ...
export class MyComponent implements OnInit {
person$: Observable<Map<string,any>>;
constructor(private ngRedux: ngRedux) { }
ngOnInit() {

constructor(private ngRedux: ngRedux) {
// even if the reference of the object has changed,
// if the data is the same - it wont be treated as a change
this.person$ = this.ngRedux.select(state=>state.people.get(0),is);
}
}
```
}
}
```
Loading

0 comments on commit 51bd0a2

Please sign in to comment.