Home - FadiZahhar/reduxJquery GitHub Wiki

πŸ• 1-Hour Training: Redux State Management in jQuery Apps


🎯 Session Outline

  1. Introduction to State Management (10 min)
  2. What is Redux? Core Principles (10 min)
  3. Why Use Redux with jQuery? (10 min)
  4. How to Use Redux in jQuery Apps (15 min)
  5. Live Demo: Task List Example (15 min)
  6. Q&A and Best Practices (10 min)

1. Why State Management Matters

  • 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.

2. What is Redux?

  • 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.

3. Why Use Redux with jQuery?

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.

4. How Does Redux Work? (With jQuery)

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

5. Live Demo: Task List Example

Store & Reducer

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);

Rendering & Events

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') });
});

HTML

<input id="taskIn" type="text">
<button id="addBtn">Add Task</button>
<ul id="list"></ul>

6. Best Practices


7. Q&A

  • 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.

8. Key Takeaway

Redux brings order, reliability, and transparency to your app’s stateβ€”even with jQuery. It helps you build scalable, maintainable, and bug-resistant apps.


πŸ› οΈ Step-by-Step Tutorial to Build Task Manager App


βœ… 1. Create Folder Structure

task-manager/
β”œβ”€β”€ index.html
β”œβ”€β”€ styles/
β”‚   └── style.css
β”œβ”€β”€ scripts/
β”‚   └── app.js

βœ… 2. index.html

<!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>

βœ… 3. styles/style.css

body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
}

button.delete-btn {
  margin-left: 10px;
}

βœ… 4. scripts/app.js

// 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
});

βœ… Result

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
⚠️ **GitHub.com Fallback** ⚠️