Skip to content

Commit ea89748

Browse files
committed
Make generic component and reducer
Note: some things are still broken, in particular actions requiring middleware. I'm not sure how to fix them right now—we'll need to discuss this.
1 parent 6a22288 commit ea89748

File tree

6 files changed

+95
-84
lines changed

6 files changed

+95
-84
lines changed

examples/counter/actions/list.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1-
export const ADD_COUNTER = 'ADD_COUNTER';
2-
export const REMOVE_COUNTER = 'REMOVE_COUNTER';
1+
export const ADD_TO_LIST = 'ADD_TO_LIST';
2+
export const REMOVE_FROM_LIST = 'REMOVE_FROM_LIST';
3+
export const PERFORM_IN_LIST = 'PERFORM_IN_LIST';
34

4-
export function add() {
5+
export function addToList() {
56
return {
6-
type: ADD_COUNTER
7+
type: ADD_TO_LIST
78
};
89
}
910

10-
export function remove() {
11+
export function removeFromList(index) {
1112
return {
12-
type: REMOVE_COUNTER
13+
type: REMOVE_FROM_LIST,
14+
index
15+
};
16+
}
17+
18+
export function performInList(index, action) {
19+
return {
20+
type: PERFORM_IN_LIST,
21+
index,
22+
action
1323
};
1424
}

examples/counter/components/Counter.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
11
import React, { Component, PropTypes } from 'react';
2+
import { increment, incrementIfOdd, incrementAsync, decrement } from '../actions/counter';
23

34
class Counter extends Component {
45
render() {
5-
const { increment, incrementIfOdd, incrementAsync, decrement, counter } = this.props;
6+
const { dispatch, counter } = this.props;
67
return (
78
<p>
89
Clicked: {counter} times
910
{' '}
10-
<button onClick={increment}>+</button>
11+
<button onClick={() => dispatch(increment())}>+</button>
1112
{' '}
12-
<button onClick={decrement}>-</button>
13+
<button onClick={() => dispatch(decrement())}>-</button>
1314
{' '}
14-
<button onClick={incrementIfOdd}>Increment if odd</button>
15+
<button onClick={() => dispatch(incrementIfOdd())}>Increment if odd</button>
1516
{' '}
16-
<button onClick={() => incrementAsync()}>Increment async</button>
17+
<button onClick={() => dispatch(incrementAsync())}>Increment async</button>
1718
</p>
1819
);
1920
}
2021
}
2122

2223
Counter.propTypes = {
23-
increment: PropTypes.func.isRequired,
24-
incrementIfOdd: PropTypes.func.isRequired,
25-
incrementAsync: PropTypes.func.isRequired,
26-
decrement: PropTypes.func.isRequired,
24+
dispatch: PropTypes.func.isRequired,
2725
counter: PropTypes.number.isRequired
2826
};
2927

examples/counter/components/List.js

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,39 @@
11
import React, { Component, PropTypes } from 'react';
2-
import Counter from './Counter';
2+
import { addToList, removeFromList, performInList } from '../actions/list';
33

4-
class List extends Component {
4+
export default function list(mapItemStateToProps) {
5+
return function (Item) {
6+
return class List extends Component {
7+
static propTypes = {
8+
dispatch: PropTypes.func.isRequired,
9+
items: PropTypes.array.isRequired
10+
};
511

6-
increment(index) {
7-
let action = this.props.counterActions.increment()
8-
action.index = index
9-
this.props.dispatch(action)
10-
}
12+
render() {
13+
const { dispatch, items } = this.props;
14+
return (
15+
<div>
16+
<button onClick={() =>
17+
dispatch(addToList())
18+
}>Add counter</button>
1119

12-
decrement(index) {
13-
let action = this.props.counterActions.decrement()
14-
action.index = index
15-
this.props.dispatch(action)
16-
}
17-
18-
render() {
19-
const { add, remove, counterList, counterActions } = this.props;
20-
return (
21-
<p>
22-
{' '}
23-
<button onClick={add}>Add counter</button>
24-
{' '}
25-
<button onClick={remove}>Remove counter</button>
26-
{counterList.map((counter, counterId) => {
27-
return <Counter key={counterId} id={counterId} counter={counter} increment={this.increment.bind(this, counterId)} decrement={this.decrement.bind(this, counterId)}></Counter>
28-
})}
29-
</p>
30-
);
31-
}
20+
<br />
21+
{items.length > 0 &&
22+
<button onClick={() =>
23+
dispatch(removeFromList(items.length - 1))
24+
}>Remove counter</button>
25+
}
26+
<br />
27+
{this.props.items.map((item, index) =>
28+
<Item {...mapItemStateToProps(item)}
29+
key={index}
30+
dispatch={action =>
31+
dispatch(performInList(index, action))
32+
} />
33+
)}
34+
</div>
35+
)
36+
}
37+
}
38+
};
3239
}
33-
34-
List.propTypes = {
35-
add: PropTypes.func.isRequired,
36-
remove: PropTypes.func.isRequired,
37-
counterList: PropTypes.array.isRequired,
38-
dispatch: PropTypes.func.isRequired
39-
};
40-
41-
export default List;

examples/counter/containers/App.js

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import { bindActionCreators } from 'redux';
22
import { connect } from 'react-redux';
3-
import List from '../components/List';
4-
import * as CounterActions from '../actions/counter';
5-
import * as ListActions from '../actions/list';
63

7-
function mapStateToProps(state) {
4+
import Counter from '../components/Counter';
5+
import list from '../components/list';
6+
7+
const CounterList = list(function mapItemStateToProps(itemState) {
88
return {
9-
counterList: state.counterList
9+
counter: itemState
1010
};
11-
}
12-
13-
function mapDispatchToProps(dispatch) {
14-
let actions = bindActionCreators(ListActions, dispatch);
15-
actions.counterActions = bindActionCreators(CounterActions, dispatch);
16-
actions.dispatch = dispatch
17-
return actions;
18-
}
11+
})(Counter);
1912

20-
export default connect(mapStateToProps, mapDispatchToProps)(List);
13+
export default connect(function mapStateToProps(state) {
14+
return {
15+
items: state.counterList
16+
};
17+
})(CounterList);

examples/counter/reducers/index.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import { combineReducers } from 'redux';
22
import counter from './counter';
33
import list from './list'
44

5+
const counterList = list(counter);
6+
57
const rootReducer = combineReducers({
6-
counterList: list(counter, {
7-
add: 'ADD_COUNTER',
8-
remove: 'REMOVE_COUNTER'
9-
})
8+
counterList
109
});
1110

1211
export default rootReducer;

examples/counter/reducers/list.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
1-
export default function list(reducer, actionTypes) {
1+
import { ADD_TO_LIST, REMOVE_FROM_LIST, PERFORM_IN_LIST } from '../actions/list';
2+
3+
export default function list(reducer) {
24
return function (state = [], action) {
5+
const {
6+
index,
7+
action: innerAction
8+
} = action;
9+
310
switch (action.type) {
4-
case actionTypes.add:
5-
return [...state, reducer(undefined, action)];
6-
case actionTypes.remove:
7-
return [...state.slice(0, action.index), ...state.slice(action.index + 1)];
11+
case ADD_TO_LIST:
12+
return [
13+
...state,
14+
reducer(undefined, action)
15+
];
16+
case REMOVE_FROM_LIST:
17+
return [
18+
...state.slice(0, index),
19+
...state.slice(index + 1)
20+
];
21+
case PERFORM_IN_LIST:
22+
return [
23+
...state.slice(0, index),
24+
reducer(state[index], innerAction),
25+
...state.slice(index + 1)
26+
];
827
default:
9-
const { index, ...rest } = action;
10-
if (typeof index !== 'undefined') {
11-
return state.map((item, i) => {
12-
if(index == i) {
13-
return reducer(item, rest)
14-
} else {
15-
return item
16-
}
17-
});
18-
}
1928
return state;
2029
}
2130
}

0 commit comments

Comments
 (0)