Skip to content

Commit 624b6f7

Browse files
authored
Merge pull request #17 from weaponsforge/dev
v1.0.3
2 parents a60e8e6 + 2f637f4 commit 624b6f7

File tree

7 files changed

+194
-5
lines changed

7 files changed

+194
-5
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import PropTypes from 'prop-types'
2+
import Page from '@/common/layout/page'
3+
import Card from '@/common/ui/card'
4+
import UserListComponent from '@/domain/users/userlist'
5+
import TodoListComponent from '@/domain/redux/todolist'
6+
7+
function UsersComponent ({
8+
addUser,
9+
deleteUser,
10+
deleteTodo,
11+
addTodo
12+
}) {
13+
return (
14+
<Page>
15+
<h2>
16+
Redux Toolkit - Users
17+
</h2>
18+
19+
<p>Testing page re-renders and data rendering from multiple redux stores (Users and ToDo) inside regular and deeply-nested components.</p>
20+
21+
<button onClick={addUser}
22+
style={{ marginTop: '24px' }}>
23+
Add User
24+
</button>
25+
26+
<br /><br />
27+
<h3>Users</h3>
28+
<br />
29+
30+
{/** A deeply-nested component */}
31+
<Card>
32+
<Card>
33+
<Card>
34+
<Card>
35+
<Card>
36+
<Card>
37+
<UserListComponent deleteUser={deleteUser} />
38+
</Card>
39+
</Card>
40+
</Card>
41+
</Card>
42+
</Card>
43+
</Card>
44+
45+
<br />
46+
<button onClick={addTodo}
47+
style={{ marginTop: '24px' }}>
48+
Add Todo
49+
</button>
50+
51+
<br /><br />
52+
<h3>ToDo</h3>
53+
54+
<TodoListComponent deleteTodo={deleteTodo} />
55+
</Page>
56+
)
57+
}
58+
59+
UsersComponent.propTypes = {
60+
addUser: PropTypes.func,
61+
deleteUser: PropTypes.func
62+
}
63+
64+
export default UsersComponent
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import PropTypes from 'prop-types'
2+
import { useSelector } from 'react-redux'
3+
4+
function UserListComponent ({ deleteUser }) {
5+
const {ids, entities: users } = useSelector(state => state.users)
6+
7+
return (
8+
<ul style={{ marginTop: '24px' }}>
9+
{(ids).map(((id, index) => (
10+
<li key={index}>
11+
<span>id: {users[id].id}, {users[id].text}</span>
12+
<span>
13+
<button onClick={() => deleteUser(id)}>
14+
[ x ]
15+
</button>
16+
</span>
17+
</li>
18+
)))}
19+
</ul>
20+
)
21+
}
22+
23+
UserListComponent.propTypes = {
24+
deleteUser: PropTypes.func
25+
}
26+
27+
export default UserListComponent

client/src/lib/store/constants.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const STATES = {
2+
IDLE: 'idle',
3+
PENDING: 'pending'
4+
}
5+
6+
export {
7+
STATES
8+
}

client/src/lib/store/store.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { combineReducers } from 'redux'
22
import { configureStore } from '@reduxjs/toolkit'
33

44
import todoSlice from '@/lib/store/todos/todoSlice'
5+
import usersSlice from '@/lib/store/users/usersSlice'
56

67
// Reducers
78
const combinedReducer = combineReducers({
8-
todos: todoSlice
9+
todos: todoSlice,
10+
users: usersSlice
911
})
1012

1113
const rootReducer = (state, action) => {

client/src/lib/store/todos/todoSlice.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import {
77
createEntityAdapter
88
} from '@reduxjs/toolkit'
99

10-
const STATES = {
11-
IDLE: 'idle',
12-
PENDING: 'pending'
13-
}
10+
import { STATES } from '@/lib/store/constants'
1411

1512
// Entiti adapter
1613
const todosAdapter = createEntityAdapter({
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Notes:
2+
// https://redux.js.org/tutorials/essentials/part-6-performance-normalization#normalized-state-structure
3+
// https://redux.js.org/tutorials/essentials/part-6-performance-normalization#optimizing-the-posts-list
4+
5+
import {
6+
createSlice,
7+
createEntityAdapter
8+
} from '@reduxjs/toolkit'
9+
10+
import { STATES } from '@/lib/store/constants'
11+
12+
// Entiti adapter
13+
const usersAdapter = createEntityAdapter({
14+
selectId: (user) => user.id
15+
})
16+
17+
// Slice
18+
const usersSlice = createSlice({
19+
name: 'users',
20+
initialState: usersAdapter.getInitialState({
21+
loading: STATES.IDLE,
22+
error: '',
23+
success: '',
24+
todo: null
25+
}),
26+
reducers: {
27+
userReceived (state, action) {
28+
const id = Math.random().toString(36).substring(2, 8)
29+
30+
state.loading = STATES.IDLE
31+
state.todo = { ...action.payload, id }
32+
usersAdapter.addOne(state, state.todo)
33+
34+
},
35+
userDelete (state, action) {
36+
usersAdapter.removeOne(state, action.payload)
37+
},
38+
usersReceived (state, action) {
39+
state.loading = STATES.IDLE
40+
usersAdapter.setAll(state, action.payload)
41+
}
42+
}
43+
})
44+
45+
export const {
46+
userReceived,
47+
usersReceived,
48+
userDelete
49+
} = usersSlice.actions
50+
51+
export default usersSlice.reducer

client/src/pages/users/index.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useDispatch } from 'react-redux'
2+
import { userReceived, userDelete } from '@/lib/store/users/usersSlice'
3+
import { todoDelete, todoReceived } from '@/lib/store/todos/todoSlice'
4+
5+
import UsersComponent from '@/components/users'
6+
7+
function Users () {
8+
const dispatch = useDispatch()
9+
10+
const addUser = () => {
11+
dispatch(userReceived({
12+
text: 'User anonymous!'
13+
}))
14+
}
15+
16+
const deleteUser = (id) => {
17+
dispatch(userDelete(id))
18+
}
19+
20+
const addTodo = () => {
21+
dispatch(todoReceived({
22+
text: 'Hello, world!'
23+
}))
24+
}
25+
26+
const deleteTodo = (id) => {
27+
dispatch(todoDelete(id))
28+
}
29+
30+
return (
31+
<UsersComponent
32+
addUser={addUser}
33+
deleteUser={deleteUser}
34+
deleteTodo={deleteTodo}
35+
addTodo={addTodo}
36+
/>
37+
)
38+
}
39+
40+
export default Users

0 commit comments

Comments
 (0)