Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions client/src/components/users/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import PropTypes from 'prop-types'
import Page from '@/common/layout/page'
import Card from '@/common/ui/card'
import UserListComponent from '@/domain/users/userlist'
import TodoListComponent from '@/domain/redux/todolist'

function UsersComponent ({
addUser,
deleteUser,
deleteTodo,
addTodo
}) {
return (
<Page>
<h2>
Redux Toolkit - Users
</h2>

<p>Testing page re-renders and data rendering from multiple redux stores (Users and ToDo) inside regular and deeply-nested components.</p>

<button onClick={addUser}
style={{ marginTop: '24px' }}>
Add User
</button>

<br /><br />
<h3>Users</h3>
<br />

{/** A deeply-nested component */}
<Card>
<Card>
<Card>
<Card>
<Card>
<Card>
<UserListComponent deleteUser={deleteUser} />
</Card>
</Card>
</Card>
</Card>
</Card>
</Card>

<br />
<button onClick={addTodo}
style={{ marginTop: '24px' }}>
Add Todo
</button>

<br /><br />
<h3>ToDo</h3>

<TodoListComponent deleteTodo={deleteTodo} />
</Page>
)
}

UsersComponent.propTypes = {
addUser: PropTypes.func,
deleteUser: PropTypes.func
}

export default UsersComponent
27 changes: 27 additions & 0 deletions client/src/domain/users/userlist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'

function UserListComponent ({ deleteUser }) {
const {ids, entities: users } = useSelector(state => state.users)

return (
<ul style={{ marginTop: '24px' }}>
{(ids).map(((id, index) => (
<li key={index}>
<span>id: {users[id].id}, {users[id].text}</span>
<span>
<button onClick={() => deleteUser(id)}>
[ x ]
</button>
</span>
</li>
)))}
</ul>
)
}

UserListComponent.propTypes = {
deleteUser: PropTypes.func
}

export default UserListComponent
8 changes: 8 additions & 0 deletions client/src/lib/store/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const STATES = {
IDLE: 'idle',
PENDING: 'pending'
}

export {
STATES
}
4 changes: 3 additions & 1 deletion client/src/lib/store/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { combineReducers } from 'redux'
import { configureStore } from '@reduxjs/toolkit'

import todoSlice from '@/lib/store/todos/todoSlice'
import usersSlice from '@/lib/store/users/usersSlice'

// Reducers
const combinedReducer = combineReducers({
todos: todoSlice
todos: todoSlice,
users: usersSlice
})

const rootReducer = (state, action) => {
Expand Down
5 changes: 1 addition & 4 deletions client/src/lib/store/todos/todoSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import {
createEntityAdapter
} from '@reduxjs/toolkit'

const STATES = {
IDLE: 'idle',
PENDING: 'pending'
}
import { STATES } from '@/lib/store/constants'

// Entiti adapter
const todosAdapter = createEntityAdapter({
Expand Down
51 changes: 51 additions & 0 deletions client/src/lib/store/users/usersSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Notes:
// https://redux.js.org/tutorials/essentials/part-6-performance-normalization#normalized-state-structure
// https://redux.js.org/tutorials/essentials/part-6-performance-normalization#optimizing-the-posts-list

import {
createSlice,
createEntityAdapter
} from '@reduxjs/toolkit'

import { STATES } from '@/lib/store/constants'

// Entiti adapter
const usersAdapter = createEntityAdapter({
selectId: (user) => user.id
})

// Slice
const usersSlice = createSlice({
name: 'users',
initialState: usersAdapter.getInitialState({
loading: STATES.IDLE,
error: '',
success: '',
todo: null
}),
reducers: {
userReceived (state, action) {
const id = Math.random().toString(36).substring(2, 8)

state.loading = STATES.IDLE
state.todo = { ...action.payload, id }
usersAdapter.addOne(state, state.todo)

},
userDelete (state, action) {
usersAdapter.removeOne(state, action.payload)
},
usersReceived (state, action) {
state.loading = STATES.IDLE
usersAdapter.setAll(state, action.payload)
}
}
})

export const {
userReceived,
usersReceived,
userDelete
} = usersSlice.actions

export default usersSlice.reducer
40 changes: 40 additions & 0 deletions client/src/pages/users/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useDispatch } from 'react-redux'
import { userReceived, userDelete } from '@/lib/store/users/usersSlice'
import { todoDelete, todoReceived } from '@/lib/store/todos/todoSlice'

import UsersComponent from '@/components/users'

function Users () {
const dispatch = useDispatch()

const addUser = () => {
dispatch(userReceived({
text: 'User anonymous!'
}))
}

const deleteUser = (id) => {
dispatch(userDelete(id))
}

const addTodo = () => {
dispatch(todoReceived({
text: 'Hello, world!'
}))
}

const deleteTodo = (id) => {
dispatch(todoDelete(id))
}

return (
<UsersComponent
addUser={addUser}
deleteUser={deleteUser}
deleteTodo={deleteTodo}
addTodo={addTodo}
/>
)
}

export default Users