diff --git a/client/src/components/users/index.js b/client/src/components/users/index.js new file mode 100644 index 0000000..d947340 --- /dev/null +++ b/client/src/components/users/index.js @@ -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 ( + +

+ Redux Toolkit - Users +

+ +

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

+ + + +

+

Users

+
+ + {/** A deeply-nested component */} + + + + + + + + + + + + + + +
+ + +

+

ToDo

+ + +
+ ) +} + +UsersComponent.propTypes = { + addUser: PropTypes.func, + deleteUser: PropTypes.func +} + +export default UsersComponent diff --git a/client/src/domain/users/userlist/index.js b/client/src/domain/users/userlist/index.js new file mode 100644 index 0000000..d9d2d07 --- /dev/null +++ b/client/src/domain/users/userlist/index.js @@ -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 ( + + ) +} + +UserListComponent.propTypes = { + deleteUser: PropTypes.func +} + +export default UserListComponent diff --git a/client/src/lib/store/constants.js b/client/src/lib/store/constants.js new file mode 100644 index 0000000..5e1e7e4 --- /dev/null +++ b/client/src/lib/store/constants.js @@ -0,0 +1,8 @@ +const STATES = { + IDLE: 'idle', + PENDING: 'pending' +} + +export { + STATES +} \ No newline at end of file diff --git a/client/src/lib/store/store.js b/client/src/lib/store/store.js index 8e86db4..26f1c75 100644 --- a/client/src/lib/store/store.js +++ b/client/src/lib/store/store.js @@ -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) => { diff --git a/client/src/lib/store/todos/todoSlice.js b/client/src/lib/store/todos/todoSlice.js index dc1f51a..a442f57 100644 --- a/client/src/lib/store/todos/todoSlice.js +++ b/client/src/lib/store/todos/todoSlice.js @@ -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({ diff --git a/client/src/lib/store/users/usersSlice.js b/client/src/lib/store/users/usersSlice.js new file mode 100644 index 0000000..9e780d0 --- /dev/null +++ b/client/src/lib/store/users/usersSlice.js @@ -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 diff --git a/client/src/pages/users/index.js b/client/src/pages/users/index.js new file mode 100644 index 0000000..d48bff9 --- /dev/null +++ b/client/src/pages/users/index.js @@ -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 ( + + ) +} + +export default Users