简体   繁体   中英

Why my callback is calling multiple time with redux

I am writing a react application with redux , with avoiding the react-redux , which is technically possible if we manually handle all the dispatched events. Here is the sample code.

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

Here if I click the button the first time it prints the log to console once, but when I click the button second time it prints the the statement twice on the log, which indicates that callback from the subscribe is being called twice, why it's happening and how can I prevent that?

Looks like your component is subscribing to the store each render cycle, and because the subscription callback updates component state another render cycle is triggered.

Chances are you likely only want the component to subscribe once to your store.

You can use an effect to subscribe once to log the state when it updates. 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>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM