为什么我的回调使用Redux多次调用

问题描述

我正在使用react编写一个redux应用程序,并避免使用react-redux,如果我们手动处理所有调度的事件,从技术上讲这是可能的。这是示例代码。

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>

在这里,如果我第一次单击该按钮,它将一次将日志打印到控制台,但是当我第二次单击该按钮时,它将在语句上打印两次语句,这表明两次调用了来自订阅的回调,为什么会发生这种情况以及如何防止这种情况发生?

解决方法

好像您的组件在每个渲染周期都订阅了商店,并且由于订阅回调更新了组件状态,因此又触发了另一个渲染周期。

您可能只希望该组件一次订阅您的商店。

您可以使用效果订阅一次以记录状态更新的状态。使用效果清除功能退订。

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...