Skip to content

Commit fc41575

Browse files
committed
Breaking API changes for 1.0
Naming: * “Stateless Stores” are now called reducers. (#137 (comment)) * The “Redux instance” is now called “The Store”. (#137 (comment)) * The dispatcher is removed completely. (#166 (comment)) API changes: * <s>`composeStores`</s> is now `composeReducers`. * <s>`createDispatcher`</s> is gone. * <s>`createRedux`</s> is now `createStore`. * `<Provider>` now accepts `store` prop instead of <s>`redux`</s>. * The new `createStore` signature is `createStore(reducer: Function | Object, initialState: any, middlewares: Array | ({ getState, dispatch }) => Array)`. * If the first argument to `createStore` is an object, `composeReducers` is automatically applied to it. * The “smart” middleware signature changed. It now accepts an object instead of a single `getState` function. The `dispatch` function lets you “recurse” the middleware chain and is useful for async: #113 (comment). * The `dispatch` provided by the default thunk middleware now walks the whole middleware chain. * It is enforced now that Actions have to be plain object. Use middleware for transforming anything else into the actions. Internal changes: * The object in React context is renamed from <s>`redux`</s> to `store`. * Some tests are rewritten for clarity, focus and edge cases. * Redux in examples is now aliased to the source code for easier work on master.
1 parent d3a31b2 commit fc41575

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+791
-475
lines changed

examples/counter/containers/App.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import React from 'react';
22
import CounterApp from './CounterApp';
3-
import { createRedux } from 'redux';
3+
import { createStore } from 'redux/index';
44
import { Provider } from 'redux/react';
5-
import * as stores from '../stores';
5+
import * as reducers from '../reducers';
66

7-
const redux = createRedux(stores);
7+
const store = createStore(reducers);
88

99
export default class App {
1010
render() {
1111
return (
12-
<Provider redux={redux}>
12+
<Provider store={store}>
1313
{() => <CounterApp />}
1414
</Provider>
1515
);

examples/counter/containers/CounterApp.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { bindActionCreators } from 'redux';
2+
import { bindActionCreators } from 'redux/index';
33
import { connect } from 'redux/react';
44
import Counter from '../components/Counter';
55
import * as CounterActions from '../actions/CounterActions';
File renamed without changes.
File renamed without changes.

examples/counter/webpack.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ module.exports = {
1818
new webpack.NoErrorsPlugin()
1919
],
2020
resolve: {
21+
alias: {
22+
'redux': path.join(__dirname, '../../src')
23+
},
2124
extensions: ['', '.js']
2225
},
2326
module: {

examples/todomvc/containers/App.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React from 'react';
22
import TodoApp from './TodoApp';
3-
import { createRedux } from 'redux';
3+
import { createStore, composeReducers } from 'redux/index';
44
import { Provider } from 'redux/react';
5-
import * as stores from '../stores';
5+
import * as reducers from '../reducers';
66

7-
const redux = createRedux(stores);
7+
const reducer = composeReducers(reducers);
8+
const store = createStore(reducer);
89

910
export default class App {
1011
render() {
1112
return (
12-
<Provider redux={redux}>
13-
{() => <TodoApp />}
13+
<Provider store={store}>
14+
{() => <TodoApp /> }
1415
</Provider>
1516
);
1617
}

examples/todomvc/containers/TodoApp.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { bindActionCreators } from 'redux';
2+
import { bindActionCreators } from 'redux/index';
33
import { Connector } from 'redux/react';
44
import Header from '../components/Header';
55
import MainSection from '../components/MainSection';
File renamed without changes.
File renamed without changes.

examples/todomvc/webpack.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ module.exports = {
1818
new webpack.NoErrorsPlugin()
1919
],
2020
resolve: {
21+
alias: {
22+
'redux': path.join(__dirname, '../../src')
23+
},
2124
extensions: ['', '.js']
2225
},
2326
module: {

src/Redux.js

-53
This file was deleted.

src/Store.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import invariant from 'invariant';
2+
import isPlainObject from './utils/isPlainObject';
3+
4+
export default class Store {
5+
constructor(reducer, initialState) {
6+
invariant(
7+
typeof reducer === 'function',
8+
'Expected the reducer to be a function.'
9+
);
10+
11+
this.state = initialState;
12+
this.listeners = [];
13+
this.replaceReducer(reducer);
14+
}
15+
16+
getReducer() {
17+
return this.reducer;
18+
}
19+
20+
replaceReducer(nextReducer) {
21+
this.reducer = nextReducer;
22+
this.dispatch({ type: '@@INIT' });
23+
}
24+
25+
dispatch(action) {
26+
invariant(
27+
isPlainObject(action),
28+
'Actions must be plain objects. Use custom middleware for async actions.'
29+
);
30+
31+
const { reducer } = this;
32+
this.state = reducer(this.state, action);
33+
this.listeners.forEach(listener => listener());
34+
return action;
35+
}
36+
37+
getState() {
38+
return this.state;
39+
}
40+
41+
subscribe(listener) {
42+
const { listeners } = this;
43+
listeners.push(listener);
44+
45+
return function unsubscribe() {
46+
const index = listeners.indexOf(listener);
47+
listeners.splice(index, 1);
48+
};
49+
}
50+
}

src/components/createConnector.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import createReduxShape from '../utils/createReduxShape';
1+
import createStoreShape from '../utils/createStoreShape';
22
import identity from '../utils/identity';
33
import shallowEqual from '../utils/shallowEqual';
44
import isPlainObject from '../utils/isPlainObject';
55
import invariant from 'invariant';
66

77
export default function createConnector(React) {
88
const { Component, PropTypes } = React;
9+
const storeShape = createStoreShape(PropTypes);
910

1011
return class Connector extends Component {
1112
static contextTypes = {
12-
redux: createReduxShape(PropTypes).isRequired
13+
store: storeShape.isRequired
1314
};
1415

1516
static propTypes = {
@@ -38,12 +39,11 @@ export default function createConnector(React) {
3839

3940
constructor(props, context) {
4041
super(props, context);
41-
4242
this.state = this.selectState(props, context);
4343
}
4444

4545
componentDidMount() {
46-
this.unsubscribe = this.context.redux.subscribe(::this.handleChange);
46+
this.unsubscribe = this.context.store.subscribe(::this.handleChange);
4747
}
4848

4949
componentWillReceiveProps(nextProps) {
@@ -63,7 +63,7 @@ export default function createConnector(React) {
6363
}
6464

6565
selectState(props, context) {
66-
const state = context.redux.getState();
66+
const state = context.store.getState();
6767
const slice = props.select(state);
6868

6969
invariant(
@@ -78,7 +78,7 @@ export default function createConnector(React) {
7878
render() {
7979
const { children } = this.props;
8080
const { slice } = this.state;
81-
const { redux: { dispatch } } = this.context;
81+
const { store: { dispatch } } = this.context;
8282

8383
return children({ dispatch, ...slice });
8484
}

src/components/createProvideDecorator.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import getDisplayName from '../utils/getDisplayName';
33
export default function createProvideDecorator(React, Provider) {
44
const { Component } = React;
55

6-
return function provide(redux) {
6+
return function provide(store) {
77
return DecoratedComponent => class ProviderDecorator extends Component {
88
static displayName = `Provider(${getDisplayName(DecoratedComponent)})`;
99
static DecoratedComponent = DecoratedComponent;
1010

1111
render() {
1212
return (
13-
<Provider redux={redux}>
13+
<Provider store={store}>
1414
{() => <DecoratedComponent {...this.props} />}
1515
</Provider>
1616
);

src/components/createProvider.js

+13-15
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
1-
import createReduxShape from '../utils/createReduxShape';
1+
import createStoreShape from '../utils/createStoreShape';
22

33
export default function createProvider(React) {
44
const { Component, PropTypes } = React;
5-
6-
const reduxShapeIsRequired = createReduxShape(PropTypes).isRequired;
5+
const storeShape = createStoreShape(PropTypes);
76

87
return class Provider extends Component {
9-
static propTypes = {
10-
redux: reduxShapeIsRequired,
11-
children: PropTypes.func.isRequired
8+
static childContextTypes = {
9+
store: storeShape.isRequired
1210
};
1311

14-
static childContextTypes = {
15-
redux: reduxShapeIsRequired
12+
static propTypes = {
13+
children: PropTypes.func.isRequired
1614
};
1715

1816
getChildContext() {
19-
return { redux: this.state.redux };
17+
return { store: this.state.store };
2018
}
2119

2220
constructor(props, context) {
2321
super(props, context);
24-
this.state = { redux: props.redux };
22+
this.state = { store: props.store };
2523
}
2624

2725
componentWillReceiveProps(nextProps) {
28-
const { redux } = this.state;
29-
const { redux: nextRedux } = nextProps;
26+
const { store } = this.state;
27+
const { store: nextStore } = nextProps;
3028

31-
if (redux !== nextRedux) {
32-
const nextDispatcher = nextRedux.getDispatcher();
33-
redux.replaceDispatcher(nextDispatcher);
29+
if (store !== nextStore) {
30+
const nextReducer = nextStore.getReducer();
31+
store.replaceReducer(nextReducer);
3432
}
3533
}
3634

src/createDispatcher.js

-26
This file was deleted.

src/createRedux.js

-13
This file was deleted.

src/createStore.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Store from './Store';
2+
import composeReducers from './utils/composeReducers';
3+
import composeMiddleware from './utils/composeMiddleware';
4+
import thunkMiddleware from './middleware/thunk';
5+
6+
const defaultMiddlewares = ({ dispatch, getState }) => [
7+
thunkMiddleware({ dispatch, getState })
8+
];
9+
10+
export default function createStore(
11+
reducer,
12+
initialState,
13+
middlewares = defaultMiddlewares
14+
) {
15+
const finalReducer = typeof reducer === 'function' ?
16+
reducer :
17+
composeReducers(reducer);
18+
19+
const store = new Store(finalReducer, initialState);
20+
const getState = ::store.getState;
21+
22+
const rawDispatch = ::store.dispatch;
23+
let cookedDispatch = null;
24+
25+
function dispatch(action) {
26+
return cookedDispatch(action);
27+
}
28+
29+
const finalMiddlewares = typeof middlewares === 'function' ?
30+
middlewares({ dispatch, getState }) :
31+
middlewares;
32+
33+
cookedDispatch = composeMiddleware(
34+
...finalMiddlewares,
35+
rawDispatch
36+
);
37+
38+
return {
39+
dispatch: cookedDispatch,
40+
subscribe: ::store.subscribe,
41+
getState: ::store.getState,
42+
getReducer: ::store.getReducer,
43+
replaceReducer: ::store.replaceReducer
44+
};
45+
}

0 commit comments

Comments
 (0)