Skip to content

Commit be5b7d7

Browse files
committed
chore: Create and implement a basic todos redux store
1 parent 35e702c commit be5b7d7

File tree

10 files changed

+316
-7
lines changed

10 files changed

+316
-7
lines changed

client/jsconfig.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
{
22
"compilerOptions": {
33
"paths": {
4-
"@/*": ["./src/*"]
4+
"@/*": ["./src/*"],
5+
"@/hooks/*": ["./src/lib/hooks/*"],
6+
"@/public/*": ["./public/*"],
7+
"@/services/*": ["./src/lib/services/*"],
8+
"@/store/*": ["./src/lib/store/*"],
9+
"@/utils/*": ["./src/lib/utils/*"]
510
}
611
}
712
}

client/package-lock.json

Lines changed: 154 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
"export": "npm run build && next export"
1616
},
1717
"dependencies": {
18+
"@reduxjs/toolkit": "^1.9.3",
1819
"eslint": "8.36.0",
1920
"eslint-config-next": "13.2.4",
2021
"next": "13.2.4",
2122
"react": "18.2.0",
22-
"react-dom": "18.2.0"
23+
"react-dom": "18.2.0",
24+
"react-redux": "^8.0.5"
2325
}
2426
}

client/src/components/home/index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Link from 'next/link'
22
import Page from '@/common/layout/page'
33
import { Inter } from 'next/font/google'
44
import styles from '@/styles/Home.module.css'
5+
import navlinks from './items.json'
56

67
const inter = Inter({ subsets: ['latin'] })
78

@@ -16,9 +17,11 @@ export default function HomeComponent() {
1617
</h1>
1718
</div>
1819

19-
<Link href="/usesyncexternalstore" className={styles.card}>
20-
useSyncExternalStore
21-
</Link>
20+
{navlinks.map((item, index) => (
21+
<Link href={item.link} key={index} className={styles.card}>
22+
{item.name}
23+
</Link>
24+
))}
2225
</div>
2326
</main>
2427
</Page>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"name": "useSyncExternalStore",
4+
"link": "/usesyncexternalstore"
5+
},
6+
{
7+
"name": "redux toolkit",
8+
"link": "/redux"
9+
}
10+
]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import PropTypes from 'prop-types'
2+
import Page from '@/common/layout/page'
3+
4+
function ReduxComponent ({
5+
todos,
6+
addTodo,
7+
deleteTodo
8+
}) {
9+
return (
10+
<Page>
11+
<h2>
12+
Redux Toolkit
13+
</h2>
14+
15+
<button onClick={addTodo}
16+
style={{ marginTop: '24px' }}>
17+
Add Todo
18+
</button>
19+
20+
<ul style={{ marginTop: '24px' }}>
21+
{(todos).map(((item, id) => (
22+
<li key={id}>
23+
<span>id: {item.id}, {item.text}</span>
24+
<span>
25+
<button onClick={() => deleteTodo(item.id)}>
26+
[ x ]
27+
</button>
28+
</span>
29+
</li>
30+
)))}
31+
</ul>
32+
</Page>
33+
)
34+
}
35+
36+
export default ReduxComponent

client/src/lib/store/store.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { combineReducers } from 'redux'
2+
import { configureStore } from '@reduxjs/toolkit'
3+
4+
import todoSlice from '@/lib/store/todos/todoSlice'
5+
6+
// Reducers
7+
const combinedReducer = combineReducers({
8+
todos: todoSlice
9+
})
10+
11+
const rootReducer = (state, action) => {
12+
return combinedReducer(state, action)
13+
}
14+
15+
// Global store
16+
export const store = configureStore({
17+
reducer: rootReducer
18+
})
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {
2+
createSlice,
3+
createEntityAdapter
4+
} from '@reduxjs/toolkit'
5+
6+
const STATES = {
7+
IDLE: 'idle',
8+
PENDING: 'pending'
9+
}
10+
11+
const todosAdapter = createEntityAdapter({
12+
selectId: (todo) => todo.id
13+
})
14+
15+
const todoSlice = createSlice({
16+
name: 'todos',
17+
initialState: todosAdapter.getInitialState({
18+
loading: STATES.IDLE,
19+
error: '',
20+
success: '',
21+
todo: null
22+
}),
23+
reducers: {
24+
todoReceived (state, action) {
25+
const id = Math.random().toString(36).substring(2, 8)
26+
27+
state.loading = STATES.IDLE
28+
state.todo = { ...action.payload, id }
29+
todosAdapter.addOne(state, state.todo)
30+
31+
},
32+
todoDelete (state, action) {
33+
todosAdapter.removeOne(state, action.payload)
34+
},
35+
todosReceived (state, action) {
36+
state.loading = STATES.IDLE
37+
todosAdapter.setAll(state, action.payload)
38+
}
39+
}
40+
})
41+
42+
export const {
43+
todoReceived,
44+
todosReceived,
45+
todoDelete
46+
} = todoSlice.actions
47+
48+
export default todoSlice.reducer

0 commit comments

Comments
 (0)