Why does my Redux callback keep getting invoked multiple times?

In developing a react application with redux, I have chosen to avoid using react-redux by manually handling all dispatched events. Below is a sample code snippet.

The content of index.html

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"></script>
</head>
<body>
  <div id="app"></div>
  <script>

  const appState= {
    count: 0,
   }

  const reducer = (state, action) => {
    if (typeof state === 'undefined') state = appState;
    switch (action.type) {
      case 'INCREMENT':
        return {count: state.count+1}
      case 'DECREMENT':
        return {count: state.count-1}
      default:
        return state
    }
  }

   var store = Redux.createStore(reducer);

  const App = () => {
    const [val, setVal] = React.useState(0);
  
    handleClick = () => {
      store.dispatch({type: 'INCREMENT'})
    }
  
    const unsubscribe = store.subscribe(() => {
      const state = store.getState();
      console.log("Listener is called")
      setVal(state.count);
    });
  
    /* unsubscribe() */;
  
    return (
      <div>
       <span>{val}</span>
        <button onClick={handleClick}>Click</button>
      </div>
    );
  }
     ReactDOM.render(<App />, document.querySelector("#app"))
  </script>
</body>
</html>

After clicking the button for the first time, it logs to the console once. However, on the second click, the log statement appears twice, indicating that the callback from the subscribe function is being called twice. How can this duplication be prevented?

Answer №1

It seems like your component is subscribing to the store every render cycle, causing a loop where the subscription callback updates the component state and triggers another render cycle.

The solution is to ensure that the component only subscribes once to the store.

You can achieve this by using an effect to subscribe once and log the state when it updates. Remember to use the effect cleanup function to unsubscribe.

const App = () => {
  const [val, setVal] = React.useState(0);

  handleClick = () => {
    store.dispatch({type: 'INCREMENT'})
  }

  useEffect(() => {
    const unsubscribe = store.subscribe(() => {
      const state = store.getState();
      console.log("Listener is called", state.count);
      setVal(state.count);
    });

    /* unsubscribe() */;
    return unsubscribe; // <-- return cleanup function
  }, []); // <-- empty dependency array to run once on mount

  return (
    <div>
      <span>{val}</span>
      <button onClick={handleClick}>Click</button>
    </div>
  );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide on leveraging Next-auth for managing multiple sessions concurrently

I am currently developing an integration tool similar to Zappier. My goal is to utilize Next-auth for connecting to multiple applications and saving their access tokens. However, I have encountered a limitation with Next-auth only allowing for one sessio ...

Using dot notation for event handlers in Vue.Js is a handy technique

I am currently developing a Single Page Application (SPA) using Vue.js 3 and Bootstrap 5. On the main page, I have implemented the Bootstrap Offcanvas element with code that closely resembles the one provided in the documentation. The structure of the off ...

Understanding the error handling in Express.js

Learning about error handling in express is new to me and I have a straightforward piece of code like this - const express = require('express'); const MongoClient = require('mongodb').MongoClient; const app = express(); let url = &a ...

Exploring the wonders of Next.js and its ability to incorporate

I am currently working on a Next.js (13.3.0) project and facing an issue with global styles that include animations. Here is the structure of my folders: https://i.stack.imgur.com/nM5xw.png All SCSS files are loaded through the master.scss file: @import & ...

ReactJS Application: Issue with Selective Mobile Scrolling

I've been working on a ReactJS web app where we mainly use styled-components for styling, but also sometimes utilize index.css for global styles (such as body and html). The application consists of an app header, a page header, and a container with a ...

When using React, the event.target method may unexpectedly return the innerText of a previously clicked element instead of the intended element that was

I have implemented a drop-down menu that triggers an event handler to return the selected option when it is clicked. Upon clicking on an option, I retrieve the inner text of that option using the event. The code snippet looks like this: event.target.inner ...

Is there a way to arrange an HTML list in this specific manner using CSS or JavaScript?

I need to arrange a list of items in columns with 5 rows each, as shown in the attached image. This list is generated dynamically using an SQL query with a loop on the li tag. I am looking for a solution to order the list in this way using javascript or ...

Use PipeTransform to apply multiple filters simultaneously

Is it possible to apply multiple filters with PipeTransform? I attempted the following: posts; postss; transform(items: any[]): any[] { if (items && items.length) this.posts = items.filter(it => it.library = it.library ...

How can I retrieve the data passed in a post request using Azure Functions and JavaScript?

I have a JavaScript Azure function that takes a context and request as parameters: function(context, req) It's easy to retrieve data from a GET request using the req object. For example, if I pass name=test in the URL, I can retrieve it in my code l ...

Looking to retrieve a JavaScript code block from an AJAX response using jQuery?

How can I extract a Javascript code block from an ajax response using jQuery, while disregarding other tags (in this case, the div tag) and prevent the execution or evaluation of the Javascript code? Example in get_js.html: <script> $(function ...

Retrieve a targeted table from a webpage through Ajax refresh

On a webpage, I have a table that has two different views: simple and collapsible. I want to be able to toggle between these views using a button click without the need to refresh the entire page. Below is the code snippet I am currently using: $(&apo ...

Tips for effectively sending prop to a component in React with the help of TypeScript

Hey there, I'm working on a component called FormField which can accept either an icon for create or edit. Currently, I am using this FormField inside another component called SelectWithFormField. Here's how it looks: const FormField = ({create, ...

tips for efficiently using keyboard to navigate through tabs in an unordered list

Utilizing unordered lists in this web application. I am looking to implement tab navigation with keyboard functionality. How can I achieve this? The first tab should contain text boxes, and when the user fills out a text box and presses the tab key, they s ...

Angular JS Tab Application: A Unique Way to Organize

I am in the process of developing an AngularJS application that includes tabs and dynamic content corresponding to each tab. My goal is to retrieve the content from a JSON file structured as follows: [ { "title": "Hello", "text": "Hi, my name is ...

The decision will be dependent on the outcomes provided by the $resource promise

I have been working on calling my API with AngularJS to retrieve a list of 'reports' and then displaying them in a modal or saving the sale depending on whether any results were returned. I've been struggling with this for a while and would ...

Iterate through the JSON response and send it back to Jquery

I'm almost done with my first jQuery autocomplete script and just need some assistance in understanding how to make the found elements clickable as links. Here is a snippet of my JavaScript code: $(document).ready(function() { var attr = $(&apos ...

Here is a unique rewrite: "Strategies for effectively passing the data variable in the geturldata function within Vue.js on the HTML side vary

How can I properly pass a variable in the getdataurl function in Vue.js? I need help with passing a variable in getdataurl function in Vue.js. Please provide a clear explanation and include as much detail as possible. I have tried doing some background r ...

The function Getter is expected, but an error has occurred with "getters.doubleCounter" returning a value of 20 in VUEX

Currently, I am diving into the world of Vuex and encountering some challenges along the way. In my attempt to create a getter on my vuex instance, I am facing an error when trying to display data from one of my components: The getter should be a functi ...

Is there a different option available in place of the JavaScript confirm function?

I developed an application where I heavily utilized the javascript confirm function. confirm("Do you want to proceed"); However, I am not satisfied with the default appearance of the confirm dialog and would like to implement a customized version with be ...

Having trouble with the Aurelia JSPM install -y command not functioning properly on Windows

I am currently following the Aurelia tutorial at I am attempting to install Aurelia dependencies using Gulp and JSPM. I successfully ran "jspm install -y" without any issues. However, upon opening the browser console, I encountered the following error: ...