Home - FadiZahhar/reduxJquery GitHub Wiki
- Introduction to State Management (10 min)
- What is Redux? Core Principles (10 min)
- Why Use Redux with jQuery? (10 min)
- How to Use Redux in jQuery Apps (15 min)
- Live Demo: Task List Example (15 min)
- Q&A and Best Practices (10 min)
- Apps are more dynamic: Users add/remove data, switch views, collaborate.
- Without structure, state gets scattered:
- JS variables
- Data attributes in HTML
- DOM nodes
- This leads to bugs, UI inconsistencies, and hard-to-maintain code.
- Redux is a predictable state container for JavaScript apps.
-
Key ideas:
- Single Source of Truth: State is in a single object.
- State is Read-Only: Mutate only via actions.
- Pure Functions: Reducers change state based on actions.
With jQuery Only | With Redux + jQuery |
---|---|
Data lives in many places | Data is centralized in Redux |
UI can get out of sync | UI always reflects the state |
Hard to debug | State/history easy to inspect |
- Redux is not just for Reactβitβs framework-agnostic!
- Works in plain JS and jQuery projects.
Redux:
- Store holds the app state
- Actions describe state changes
- Reducers handle state transitions
jQuery:
- Handles rendering and user interaction
- Dispatches actions to Redux
- Subscribes to Redux state changes to update UI
const initialState = { tasks: [] };
function tasksReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TASK': return { ...state, tasks: [...state.tasks, action.payload] };
case 'DELETE_TASK': return { ...state, tasks: state.tasks.filter((_, i) => i !== action.payload) };
default: return state;
}
}
const store = Redux.createStore(tasksReducer);
function render() {
const { tasks } = store.getState();
$('#list').empty();
tasks.forEach((task, i) =>
$('#list').append(`<li>${task} <button class="del" data-i="${i}">X</button></li>`)
);
}
store.subscribe(render);
render();
$('#addBtn').click(() => {
const val = $('#taskIn').val();
if (val) store.dispatch({ type: 'ADD_TASK', payload: val });
});
$('#list').on('click', '.del', function() {
store.dispatch({ type: 'DELETE_TASK', payload: $(this).data('i') });
});
<input id="taskIn" type="text">
<button id="addBtn">Add Task</button>
<ul id="list"></ul>
- Keep reducers pure (no side effects!)
- Always use actions to change state (never mutate directly)
- Organize code: split reducers, actions, rendering logic
- Use [Redux DevTools](https://redux.js.org/usage/configuring-your-store#using-the-redux-devtools-extension) for debugging
- When to use Redux in jQuery? When app state is shared or complex.
- Is Redux overkill for tiny apps? For small widgets, maybe. For interactive, multi-user, or collaborative apps, Redux is worth it.
Redux brings order, reliability, and transparency to your appβs stateβeven with jQuery. It helps you build scalable, maintainable, and bug-resistant apps.
task-manager/
βββ index.html
βββ styles/
β βββ style.css
βββ scripts/
β βββ app.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Redux + jQuery Task Manager</title>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css" />
<link rel="stylesheet" href="styles/style.css" />
</head>
<body>
<div class="w3-container w3-light-grey w3-card w3-padding" style="max-width: 600px; margin: auto; margin-top: 40px;">
<h2 class="w3-center">Task Manager</h2>
<input id="taskInput" class="w3-input w3-margin-bottom" type="text" placeholder="Add a new task..." />
<button id="addTaskBtn" class="w3-button w3-teal w3-block">Add Task</button>
<ul id="taskList" class="w3-ul w3-card-2 w3-margin-top"></ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
}
button.delete-btn {
margin-left: 10px;
}
// STEP 1: Define initial state
const initialState = {
tasks: [],
loading: false,
error: null
};
// STEP 2: Define reducer
function taskReducer(state = initialState, action) {
switch (action.type) {
case 'SET_LOADING':
return { ...state, loading: true, error: null };
case 'SET_TASKS':
return { ...state, tasks: action.payload, loading: false };
case 'SET_ERROR':
return { ...state, error: action.payload, loading: false };
case 'ADD_TASK':
return { ...state, tasks: [...state.tasks, action.payload] };
case 'DELETE_TASK':
return { ...state, tasks: state.tasks.filter((_, i) => i !== action.payload) };
default:
return state;
}
}
// STEP 3: Create Redux store
const store = Redux.createStore(taskReducer);
// STEP 4: Async fetch using jQuery
function fetchTasks() {
store.dispatch({ type: 'SET_LOADING' });
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos?_limit=5',
method: 'GET',
success: function (data) {
const taskTitles = data.map(task => task.title);
store.dispatch({ type: 'SET_TASKS', payload: taskTitles });
},
error: function (_, __, errorThrown) {
store.dispatch({ type: 'SET_ERROR', payload: errorThrown });
}
});
}
// STEP 5: Dispatch actions
function addTask(task) {
store.dispatch({ type: 'ADD_TASK', payload: task });
}
function deleteTask(index) {
store.dispatch({ type: 'DELETE_TASK', payload: index });
}
// STEP 6: DOM interactions with jQuery
$(function () {
const $taskList = $('#taskList');
const $taskInput = $('#taskInput');
function render() {
const { tasks, loading, error } = store.getState();
$taskList.empty();
if (loading) return $taskList.append('<li>Loading...</li>');
if (error) return $taskList.append(`<li class="w3-text-red">Error: ${error}</li>`);
tasks.forEach((task, i) => {
$taskList.append(`
<li>
${task}
<button class="delete-btn w3-button w3-red w3-small w3-right" data-index="${i}">X</button>
</li>
`);
});
}
// Subscribe Redux store to render UI
store.subscribe(render);
// Add new task
$('#addTaskBtn').click(() => {
const task = $taskInput.val().trim();
if (task) {
addTask(task);
$taskInput.val('');
}
});
// Delete task
$taskList.on('click', '.delete-btn', function () {
const index = $(this).data('index');
deleteTask(index);
});
// Fetch initial tasks from API
fetchTasks();
render(); // First UI render
});
Youβll have a working, modern, responsive Redux + jQuery task app that:
- β Loads 5 tasks from an API on page load
- β Adds new tasks dynamically
- β Deletes tasks from the list
- β Uses Redux (no Thunk) for all state management
- β Uses jQuery for DOM