From 5e9d926e9290f9afa7bb62c223ae3d2c90937d2f Mon Sep 17 00:00:00 2001 From: weaponsforge Date: Sun, 19 Mar 2023 18:03:12 +0800 Subject: [PATCH 1/2] chore: Create a users redux store for testing multiple stores --- client/src/components/users/index.js | 48 +++++++++++++++++++++ client/src/domain/users/userlist/index.js | 27 ++++++++++++ client/src/lib/store/constants.js | 8 ++++ client/src/lib/store/store.js | 4 +- client/src/lib/store/todos/todoSlice.js | 5 +-- client/src/lib/store/users/usersSlice.js | 51 +++++++++++++++++++++++ client/src/pages/users/index.js | 27 ++++++++++++ 7 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 client/src/components/users/index.js create mode 100644 client/src/domain/users/userlist/index.js create mode 100644 client/src/lib/store/constants.js create mode 100644 client/src/lib/store/users/usersSlice.js create mode 100644 client/src/pages/users/index.js diff --git a/client/src/components/users/index.js b/client/src/components/users/index.js new file mode 100644 index 0000000..39dda0c --- /dev/null +++ b/client/src/components/users/index.js @@ -0,0 +1,48 @@ +import PropTypes from 'prop-types' +import Page from '@/common/layout/page' +import Card from '@/common/ui/card' +import UserListComponent from '@/domain/users/userlist' + +function UsersComponent ({ + addUser, + deleteUser +}) { + return ( + +

+ Redux Toolkit - Users +

+ +

Testing page re-renders and data rendering from a redux store inside a deeply-nested component.

+ + + +

+ + {/** A deeply-nested component */} + + + + + + + + + + + + + +
+ ) +} + +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..a5459e3 --- /dev/null +++ b/client/src/pages/users/index.js @@ -0,0 +1,27 @@ +import { useDispatch } from 'react-redux' +import { userReceived, userDelete } from '@/lib/store/users/usersSlice' + +import UsersComponent from '@/components/users' + +function Users () { + const dispatch = useDispatch() + + const addUser = () => { + dispatch(userReceived({ + text: 'User anonymous!' + })) + } + + const deleteUser = (id) => { + dispatch(userDelete(id)) + } + + return ( + + ) +} + +export default Users From 6caeef3138c787dcac64744b9a9d6a933e4d9ca5 Mon Sep 17 00:00:00 2001 From: weaponsforge Date: Sun, 19 Mar 2023 18:10:56 +0800 Subject: [PATCH 2/2] chore: Test page re-renders when loading and processing multiple redux stores --- client/src/components/users/index.js | 20 ++++++++++++++++++-- client/src/pages/users/index.js | 13 +++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/client/src/components/users/index.js b/client/src/components/users/index.js index 39dda0c..d947340 100644 --- a/client/src/components/users/index.js +++ b/client/src/components/users/index.js @@ -2,10 +2,13 @@ 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 + deleteUser, + deleteTodo, + addTodo }) { return ( @@ -13,7 +16,7 @@ function UsersComponent ({ Redux Toolkit - Users -

Testing page re-renders and data rendering from a redux store inside a deeply-nested component.

+

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 */} @@ -36,6 +41,17 @@ function UsersComponent ({ + +
+ + +

+

ToDo

+ +
) } diff --git a/client/src/pages/users/index.js b/client/src/pages/users/index.js index a5459e3..d48bff9 100644 --- a/client/src/pages/users/index.js +++ b/client/src/pages/users/index.js @@ -1,5 +1,6 @@ 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' @@ -16,10 +17,22 @@ function Users () { dispatch(userDelete(id)) } + const addTodo = () => { + dispatch(todoReceived({ + text: 'Hello, world!' + })) + } + + const deleteTodo = (id) => { + dispatch(todoDelete(id)) + } + return ( ) }