|
3 | 3 |
|
4 | 4 | For Angular 1 see [ng-redux](https://github.com/wbuchwalter/ng-redux) |
5 | 5 |
|
6 | | -##### This is a work very much in progress, use at your own risk :) |
7 | | - |
8 | | -## Overview |
9 | | - |
10 | 6 | ngRedux lets you easily connect your angular components with Redux. |
11 | 7 |
|
12 | | -```JS |
13 | | -ngRedux.connect(selector, callback, disableCaching = false); |
14 | | -//OR |
15 | | -ngRedux.connect([selector1, selector2, ...], callback, disableCaching = false); |
16 | | -``` |
17 | | - |
18 | | -Where selector is a function taking for single argument the entire redux Store's state (a plain JS object) and returns another object, which is the slice of the state that your component is interested in. |
19 | | -e.g: |
20 | | -```JS |
21 | | -state => state.todos |
22 | | -``` |
23 | | -Note: if you are not familiar with this syntax, go and check out the [MDN Guide on fat arrow functions (ES2015)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) |
24 | 8 |
|
25 | | -If you haven't, check out [reselect](https://github.com/faassen/reselect), an awesome tool to create and combine selectors. |
| 9 | +## Table of Contents |
26 | 10 |
|
| 11 | +- [Installation](#installation) |
| 12 | +- [Quick Start](#quick-start) |
| 13 | +- [API](#api) |
| 14 | +- [Using DevTools](#using-devtools) |
27 | 15 |
|
28 | | -The returned object will be passed as argument to the callback provided whenever the state changes. |
29 | | -ngRedux checks for shallow equality of the state's selected slice whenever the Store is updated, and will call the callback only if there is a change. |
30 | | -##### Important: It is assumed that you never mutate your states, if you do mutate them, ng-redux will not execute the callback properly. |
31 | | -See [Redux's doc](http://gaearon.github.io/redux/docs/basics/Reducers.html) to understand why you should not mutate your states. |
32 | | -If you have a good reason to mutate your states, you can still [disable caching](#Disable-caching) altogether. |
| 16 | +## Installation |
33 | 17 |
|
| 18 | +```js |
| 19 | +npm install --save ng2-redux |
| 20 | +``` |
34 | 21 |
|
35 | | -## Getting Started |
| 22 | +## Quick Start |
36 | 23 |
|
37 | 24 | #### Initialization |
38 | | -You need to pass Redux Store to ng-redux via ```$ngReduxProvider``` : |
39 | 25 |
|
40 | 26 | ```JS |
| 27 | +import {bootstrap} from 'angular2/angular2'; |
| 28 | +import {bind} from 'angular2/di'; |
| 29 | +import {createStore, applyMiddleware} from 'redux'; |
| 30 | +import thunk from 'redux-thunk'; |
| 31 | +import {App} from './containers/App'; |
| 32 | +import {provide} from 'ng2-redux'; |
| 33 | +import {rootReducer} from './reducers'; |
| 34 | + |
41 | 35 | const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); |
42 | 36 | const store = createStoreWithMiddleware(rootReducer); |
43 | 37 |
|
44 | 38 | bootstrap( |
45 | 39 | App, |
46 | | - [bind('ngRedux').toFactory(() => { |
47 | | - return new ngRedux(store); |
48 | | - })] |
49 | | -); |
| 40 | + [provide(store)] |
| 41 | + ); |
50 | 42 | ``` |
51 | 43 |
|
52 | 44 | #### Usage |
| 45 | + |
53 | 46 | ```JS |
54 | | -@Component(...) |
55 | | -@View(...) |
56 | | -class SmartComponent { |
| 47 | +import * as CounterActions from '../actions/CounterActions'; |
57 | 48 |
|
58 | | - constructor(@Inject('ngRedux') ngRedux) { |
59 | | - this._ngRedux = ngRedux; |
60 | | - ngRedux.connect(state => state.counter, counter => this.counter = counter); |
| 49 | +class CounterApp { |
| 50 | + constructor( @Inject('ngRedux') ngRedux) { |
| 51 | + this.unsubscribe = ngRedux.connect(this.mapStateToScope, this.mapDispatchToProps)(this); |
61 | 52 | } |
62 | 53 |
|
63 | | - onInit() { |
64 | | - this.actions = bindActionCreators(CounterActions, this._ngRedux.getStore().dispatch); |
65 | | - } |
| 54 | + onInit() {} |
66 | 55 |
|
67 | 56 | onDestroy() { |
68 | | - this._ngRedux.disconnect(); |
| 57 | + this.unsubscribe(); |
| 58 | + } |
| 59 | + |
| 60 | + mapStateToScope(state) { |
| 61 | + return { |
| 62 | + counter: state.counter |
| 63 | + }; |
| 64 | + } |
| 65 | + |
| 66 | + mapDispatchToProps(dispatch) { |
| 67 | + return { actions: bindActionCreators(CounterActions, dispatch) }; |
69 | 68 | } |
70 | 69 | } |
71 | 70 | ``` |
72 | 71 |
|
73 | | -##### Note: The callback provided to ```connect``` will be called once directly after creation to allow initialization of your component states |
| 72 | +## API |
74 | 73 |
|
| 74 | +### `provide(store)` |
75 | 75 |
|
| 76 | +Provide the Redux store to `connect`. |
76 | 77 |
|
77 | | -You can also grab multiple slices of the state by passing an array of selectors: |
| 78 | +#### Arguments: |
| 79 | +* `store` \(*Object*): Redux's store instance |
78 | 80 |
|
79 | | -```JS |
80 | | - ngRedux.connect([ |
81 | | - state => state.todos, |
82 | | - state => state.users |
83 | | - ], |
84 | | - (todos, users) => { |
85 | | - this.todos = todos |
86 | | - this.users = users; |
87 | | - }); |
88 | | -``` |
| 81 | +### `connect(mapStateToTarget, [mapDispatchToTarget])(target)` |
89 | 82 |
|
| 83 | +Connects an Angular component to Redux. |
90 | 84 |
|
91 | | -#### Accessing Redux' Store |
92 | | -You don't need to create another service to get hold of Redux's store (although you can). |
93 | | -You can access the store via ```ngRedux.getStore()```: |
| 85 | +#### Arguments |
| 86 | +* `mapStateToTarget` \(*Function*): connect will subscribe to Redux store updates. Any time it updates, mapStateToTarget will be called. Its result must be a plain object, and it will be merged into `target`. If you have a component which simply triggers actions without needing any state you can pass null to `mapStateToTarget`. |
| 87 | +* [`mapDispatchToTarget`] \(*Object* or *Function*): Optional. If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged onto `target`. If a function is passed, it will be given `dispatch`. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.). |
94 | 88 |
|
95 | | -```JS |
96 | | -redux.bindActionCreators(actionCreator, ngRedux.getStore().dispatch); |
| 89 | +*You then need to invoke the function a second time, with `target` as parameter:* |
| 90 | +* `target` \(*Object* or *Function*): If passed an object, the results of `mapStateToTarget` and `mapDispatchToTarget` will be merged onto it. If passed a function, the function will receive the results of `mapStateToTarget` and `mapDispatchToTarget` as parameters. |
| 91 | + |
| 92 | +e.g: |
| 93 | +```JS |
| 94 | +connect(this.mapState, this.mapDispatch)(this); |
| 95 | +//Or |
| 96 | +connect(this.mapState, this.mapDispatch)((selectedState, actions) => {/* ... */}); |
97 | 97 | ``` |
98 | 98 |
|
99 | | -#### Disabling caching |
100 | | -Each time Redux's Store update, ng-redux will check if the slices specified via 'selectors' have changed, and if so will execute the provided callback. |
101 | | -You can disable this behaviour, and force the callback to be executed even if the slices didn't change by setting ```disableCaching``` to true: |
| 99 | + |
| 100 | +#### Remarks |
| 101 | +* The `mapStateToTarget` function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. It is often called a selector. Use reselect to efficiently compose selectors and compute derived data. |
| 102 | + |
| 103 | + |
| 104 | +### Store API |
| 105 | +All of redux's store methods (i.e. `dispatch`, `subscribe` and `getState`) are exposed by $ngRedux and can be accessed directly. For example: |
102 | 106 |
|
103 | 107 | ```JS |
104 | | -reduxConnector.connect(state => state.todos, todos => this.todos = todos, true); |
| 108 | +ngRedux.subscribe(() => { |
| 109 | + let state = $ngRedux.getState(); |
| 110 | + //... |
| 111 | +}) |
105 | 112 | ``` |
| 113 | + |
| 114 | +This means that you are free to use Redux basic API in advanced cases where `connect`'s API would not fill your needs. |
| 115 | + |
| 116 | + |
| 117 | +## Using DevTools |
| 118 | +--Todo |
0 commit comments