A learning project to build a counter app using React and Redux Toolkit, including real setup experience, errors, and how to solve them.
📅 Release Date: 10 April 2025
reduxtoolkit/
├── node_modules/ # Dependency packages (auto-generated)
├── public/ # Static public assets
├── src/
│ ├── app/ # Manual add folder
│ │ └── store.js # Redux store setup
│ ├── features/ # Manual add folder
│ │ └── counter/
│ │ └── counterslice.js # Redux slice for counter logic
│ ├── App.js # Main App component
│ ├── App.css # Styling for the app
│ ├── index.js # App entry point with ReactDOM and Provider
│ └── reportWebVitals.js # Web performance reporting (optional)
├── .gitignore # Git ignored files
├── package.json # Project metadata and dependencies
├── README.md # Project documentation
└── yarn.lock / package-lock.json # Dependency lock filenpx create-react-app reduxtoolkit
cd reduxtoolkitJika hanya muncul node_modules dan package.json setelah setup, itu normal. Lanjut ke langkah berikutnya.
- Install Redux Toolkit dan React-Redux
npm install @reduxjs/toolkit react-redux- Buat Folder Manual (Jika Belum Ada) Jika folder src/app/ tidak ada, buat manual:
css
src/
├── app/
├── features/
│ │ └── counter/Berikut ini adalah daftar lengkap file dan folder yang kamu tambahkan atau edit secara manual selama proses pengembangan proyek ini. Setiap file dilengkapi dengan penjelasan dan potongan kode penting yang kamu buat atau ubah sendiri.
File ini digunakan untuk konfigurasi Redux store dan menggabungkan semua reducer.
// src/app/store.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})File ini mendefinisikan createSlice() untuk counter, dengan reducer dan actions.
// src/features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1 },
decrement: (state) => { state.value -= 1 },
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export const selectCount = (state) => state.counter.value
export default counterSlice.reducerKamu mengedit file ini untuk menyambungkan Redux ke React menggunakan <Provider>.
// src/index.js
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import App from './App'
import store from './app/store'
import reportWebVitals from './reportWebVitals'
import './index.css'
const root = createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
)
reportWebVitals()Kamu edit App.js untuk menampilkan UI counter dan menyambungkan dengan Redux menggunakan useSelector() dan useDispatch().
// src/App.js
import React from 'react'
import './App.css'
import { useSelector, useDispatch } from 'react-redux'
import {
decrement,
increment,
incrementByAmount,
selectCount,
} from './features/counter/counterSlice'
function App() {
const count = useSelector(selectCount)
const dispatch = useDispatch()
return (
<div className="App">
<h1>Redux Counter App</h1>
<p className="count">{count}</p>
<div className="buttons">
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
</div>
</div>
)
}
export default AppKamu menambahkan styling agar UI lebih menarik.
/* src/App.css */
.App {
text-align: center;
padding: 2rem;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
min-height: 100vh;
}
.count {
font-size: 4rem;
margin: 1rem 0;
}
.buttons button {
font-size: 1.5rem;
margin: 0 1rem;
padding: 0.5rem 1.5rem;
border: none;
border-radius: 10px;
background-color: #6200ee;
color: white;
cursor: pointer;
transition: background 0.3s;
}
.buttons button:hover {
background-color: #3700b3;
}- Jalankan Project
npm start- Jika muncul halaman "Edit src/App.js and save to reload", buka "src/app.js" kamu lalu copy dan paste kode dibawah ke dalam "src/app.js" kamu
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {
increment,
decrement,
incrementByAmount,
incrementAsync,
selectCount,
} from './features/counter/counterslice'
import './App.css'
function App() {
const count = useSelector(selectCount)
const dispatch = useDispatch()
const [incrementAmount, setIncrementAmount] = useState('2')
return (
<div className="container">
<h1>Redux Counter</h1>
<h2>{count}</h2>
<div>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
<div className="controls">
<input
type="number"
value={incrementAmount}
onChange={(e) => setIncrementAmount(e.target.value)}
/>
<button
onClick={() =>
dispatch(incrementByAmount(Number(incrementAmount) || 0))
}
>
Add Amount
</button>
<button
onClick={() =>
dispatch(incrementAsync(Number(incrementAmount) || 0))
}
>
Add Async
</button>
</div>
</div>
)
}
export default App🐞 Beberapa Error & Solusi ❌ Error: 'ReactDOM' is not defined
Line 8:14: 'ReactDOM' is not defined no-undef✅ Solusi: Pastikan kamu sudah mengimpor createRoot dan gunakan ini:
import { createRoot } from 'react-dom/client'
const root = createRoot(document.getElementById('root'))
root.render(<App />)❌ Error: 'reportWebVitals' is not defined ✅ Solusi: Pastikan file ini diimpor dengan benar:
⚠️ Warning:'createRoot' is defined but never used
Pastikan kamu sudah menggunakancreateRoot(...)untuk merender aplikasimu.
✨ Counter Logic (Redux Slice)
src/features/counter/counterslice.js
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1 },
decrement: (state) => { state.value -= 1 },
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export const selectCount = (state) => state.counter.value
export default counterSlice.reducer🎨 Styling (CSS) Tambahkan styling ke App.css agar tampilan lebih menarik:
body {
font-family: 'Segoe UI', sans-serif;
background-color: #f0f2f5;
display: flex;
justify-content: center;
padding: 50px;
}
.counter-container {
background: white;
padding: 2rem;
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
text-align: center;
}
.counter-container button {
margin: 0.5rem;
padding: 10px 20px;
font-size: 18px;
}☁️ Push ke GitHub Inisialisasi git:
git init
git add .
git commit -m "Initial commit"Tambahkan remote dan push:
git remote add origin https://github.com/yourusername/redux-counter.gitgit branch -M maingit push -u origin mainKalau git init sudah pernah dilakukan, dan kamu ingin mengulang dari awal:
# Batalkan git
Remove-Item -Recurse -Force .git # PowerShell
rm -rf .git # Git Bash▄▄▄█████▓ ██░ ██ ▄▄▄ ███▄ █ ██ ▄█▀
▓ ██▒ ▓▒▓██░ ██▒▒████▄ ██ ▀█ █ ██▄█▒
▒ ▓██░ ▒░▒██▀▀██░▒██ ▀█▄ ▓██ ▀█ ██▒▓███▄░
░ ▓██▓ ░ ░▓█ ░██ ░██▄▄▄▄██ ▓██▒ ▐▌██▒▓██ █▄
▒██▒ ░ ░▓█▒░██▓ ▓█ ▓██▒▒██░ ▓██░▒██▒ █▄
▒ ░░ ▒ ░░▒░▒ ▒▒ ▓▒█░░ ▒░ ▒ ▒ ▒ ▒▒ ▓▒
░ ▒ ░▒░ ░ ▒ ▒▒ ░░ ░░ ░ ▒░░ ░▒ ▒░
░ ░ ░░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░
░ ░ ░ ░ ░ ░ ░ ░
▓██ ██▓ ▒█████ █ ██
▒██ ██▒▒██▒ ██▒ ██ ▓██▒
▒██ ██░▒██░ ██▒▓██ ▒██░
░ ▐██▓░▒██ ██░▓▓█ ░██░
░ ██▒▓░░ ████▓▒░▒▒█████▓
██▒▒▒ ░ ▒░▒░▒░ ░▒▓▒ ▒ ▒
▓██ ░▒░ ░ ▒ ▒░ ░░▒░ ░ ░
▒ ▒ ░░ ░ ░ ░ ▒ ░░░ ░ ░
░ ░ ░ ░ ░
░ ░