Skip to content

Commit e867876

Browse files
committed
docs: update examples to include api actions and simple "get" selector
1 parent b2fb183 commit e867876

File tree

6 files changed

+76
-46
lines changed

6 files changed

+76
-46
lines changed

example/src/components/order/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@ import settingsDuck from '../settings/settings.duck';
99
class Order extends Component {
1010
static propTypes = {
1111
orders: PropTypes.array.isRequired,
12+
isLoading: PropTypes.bool.isRequired,
1213
fetchOrders: PropTypes.func.isRequired,
1314
};
1415

1516
render() {
16-
const { orders, fetchOrders } = this.props;
17+
const { orders, fetchOrders, isLoading } = this.props;
1718

1819
return (
1920
<Container>
2021
<h1>Order example</h1>
2122
<button onClick={fetchOrders}>Fetch orders</button>
2223

24+
{isLoading && <Loading>Loading orders..</Loading>}
25+
2326
{orders.length > 0 && (
2427
<Orders>
2528
{orders.map(order => (
@@ -36,6 +39,10 @@ const Container = styled.div`
3639
flex: 1;
3740
`;
3841

42+
const Loading = styled.div`
43+
margin-top: 16px;
44+
`;
45+
3946
const Orders = styled.ul`
4047
list-style: none;
4148
margin-top: 16px;
@@ -45,6 +52,7 @@ export default connect(
4552
state => ({
4653
// orders: orderDucks.selectors.getOrders(state),
4754
orders: orderDucks.selectors.get('orders', state),
55+
isLoading: orderDucks.selectors.getIsLoading(state),
4856
}),
4957
{
5058
testThunk: settingsDuck.actions.testThunk,
Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
import { takeEvery, put } from 'redux-saga/effects';
2-
import { createDuck } from 'reducktion'; // eslint-disable-line
2+
import { createDuck, createApiAction } from 'reducktion'; // eslint-disable-line
33
import { sleep } from '../../helpers';
44

55
const duck = createDuck({
66
name: 'order',
77
inject: ['user'],
88
state: {
99
orders: [],
10-
isLoading: false,
10+
packages: [],
11+
error: undefined,
1112
hasError: false,
13+
isLoading: false,
1214
},
1315
actions: () => ({
14-
fetchOrders: state => ({ ...state, isLoading: true }),
15-
failFetchOrders: state => ({
16-
...state,
17-
isLoading: false,
18-
hasError: true,
19-
}),
20-
receiveOrders: (state, action) => ({
21-
...state,
22-
isLoading: false,
23-
hasError: false,
24-
orders: action.payload,
16+
// Simple way to create API related action
17+
fetchOrders: createApiAction('orders'),
18+
// Provide custom success reducer handler
19+
fetchPackages: createApiAction({
20+
success: (state, action) => ({
21+
...state,
22+
packages: action.payload,
23+
hasError: null,
24+
isLoading: false,
25+
}),
2526
}),
2627
}),
2728
reactions: ({ deps }) => ({
@@ -39,27 +40,21 @@ const duck = createDuck({
3940

4041
// Saga handlers
4142
function* fetchOrdersSaga() {
42-
// Fake API call delay
43-
yield sleep(400);
44-
yield put(
45-
duck.actions.receiveOrders([
46-
{ id: 1, name: 'Mock order 1' },
47-
{ id: 2, name: 'Mock order 2' },
48-
{ id: 3, name: 'Mock order 3' },
49-
{ id: 4, name: 'Mock order 4' },
50-
])
51-
);
52-
53-
/* Or use manually defined actions that does the same thing as `receiveOrders`
54-
yield put(
55-
duck.actions.setOrders([
56-
{ id: 1, name: 'Mock order 1' },
57-
{ id: 2, name: 'Mock order 2' },
58-
{ id: 3, name: 'Mock order 3' },
59-
{ id: 4, name: 'Mock order 4' },
60-
])
61-
);
62-
*/
43+
try {
44+
// Fake API call delay
45+
yield sleep(400);
46+
// this.props.fetchOrders()
47+
yield put(
48+
duck.actions.fetchOrders.success([
49+
{ id: 1, name: 'Mock order 1' },
50+
{ id: 2, name: 'Mock order 2' },
51+
{ id: 3, name: 'Mock order 3' },
52+
{ id: 4, name: 'Mock order 4' },
53+
])
54+
);
55+
} catch (error) {
56+
yield put(duck.actions.fetchOrders.fail());
57+
}
6358
}
6459

6560
export default duck;

example/src/components/settings/index.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Settings extends Component {
1414
toggleNotifications: PropTypes.func.isRequired,
1515
toggleGps: PropTypes.func.isRequired,
1616
toggleDarkMode: PropTypes.func.isRequired,
17+
testThunk: PropTypes.func.isRequired,
1718
};
1819

1920
render() {
@@ -24,11 +25,15 @@ class Settings extends Component {
2425
toggleNotifications,
2526
toggleGps,
2627
toggleDarkMode,
28+
testThunk,
2729
} = this.props;
2830

2931
return (
3032
<Container>
3133
<h1>Settings example</h1>
34+
35+
<Button onClick={testThunk}>Test Thunk</Button>
36+
3237
<Options>
3338
<Label>
3439
Dark mode on
@@ -86,6 +91,16 @@ const Checkbox = styled.input.attrs({ type: 'checkbox' })`
8691
margin-left: 16px;
8792
`;
8893

94+
const Button = styled.button`
95+
padding: 8px 12px;
96+
border: none;
97+
background-color: slategray;
98+
color: #fff;
99+
border-radius: 4px;
100+
width: 200px;
101+
margin-bottom: 32px;
102+
`;
103+
89104
export default connect(
90105
state => ({
91106
gpsEnabled: settingsDuck.selectors.getGpsEnabled(state),
@@ -97,5 +112,6 @@ export default connect(
97112
toggleNotifications: settingsDuck.actions.toggleNotifications,
98113
toggleGps: settingsDuck.actions.toggleGps,
99114
toggleDarkMode: settingsDuck.actions.toggleDarkMode,
115+
testThunk: settingsDuck.actions.testThunk,
100116
}
101117
)(Settings);

example/src/components/settings/settings.duck.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,22 @@ const duck = createDuck({
2525
...state,
2626
darkModeEnabled: !state.darkModeEnabled,
2727
}),
28-
testThunk,
2928
}),
29+
thunks: { testThunk },
3030
});
3131

3232
// Thunks
33-
function testThunk(arg, { user, order }) {
33+
function testThunk(arg, { user }) {
3434
return async dispatch => {
35-
dispatch(duck.actions.updateTheme('dark'));
36-
dispatch(order.actions.setOrders());
37-
dispatch(user.actions.setProfile());
35+
dispatch(duck.actions.toggleGps());
36+
dispatch(duck.actions.toggleDarkMode());
37+
dispatch(
38+
user.actions.setProfile({
39+
name: 'New Profile',
40+
avatarUrl: 'https://source.unsplash.com/random/200x200',
41+
githubUrl: 'https://github.com/Temzasse',
42+
})
43+
);
3844
};
3945
}
4046

example/src/components/user/index.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,19 @@ const LogoutButton = styled.button`
6767
width: 120px;
6868
`;
6969

70+
// You can also destruct `selectors` and `actions` for brewity
71+
const { selectors, actions } = userDuck;
72+
7073
export default connect(
7174
state => ({
72-
isAuthenticated: userDuck.selectors.getIsAuthenticated(state),
73-
profile: userDuck.selectors.getProfile(state),
74-
loading: userDuck.selectors.getLoading(state),
75-
error: userDuck.selectors.getError(state),
75+
isAuthenticated: selectors.getIsAuthenticated(state),
76+
// profile: selectors.getProfile(state),
77+
profile: selectors.get('profile', state),
78+
loading: selectors.getLoading(state),
79+
error: selectors.getError(state),
7680
}),
7781
{
78-
login: userDuck.actions.login,
79-
logout: userDuck.actions.logout,
82+
login: actions.login,
83+
logout: actions.logout,
8084
}
8185
)(User);

example/src/components/user/user.duck.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const duck = createDuck({
2222
loading: false,
2323
error: false,
2424
}),
25+
setProfile: (state, action) => ({ ...state, profile: action.payload }),
2526
}),
2627
selectors: ({ name }) => ({
2728
getProfile: state => state[name].profile, // Custom selector just for fun

0 commit comments

Comments
 (0)