React-Redux Counter 示例动作触发两次

sha*_*haz 5 react-redux

https://codesandbox.io/s/jvj6o043yv

我正在尝试使用非常简单的 Counter 示例来了解 react-redux connect、Provider 和 mapStateToProps 和 MapDispatchToProps 的基础知识。练习的重点是将道具和动作注入到 Counter 组件中。

我看到的问题是,每次单击按钮时,我的操作都会触发两次。我是 Redux 菜鸟,所以我确定(我希望)这是一个相当基本的错误。我很感激任何指出我出错的地方。提前致谢。

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { connect } from 'react-redux'
import { createStore, applyMiddleware } from 'redux';
import { createLogger } from 'redux-logger';


// Reducer
const counter = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

// store setup
const configureStore = () => {
  const middlewares = [];
  if (process.env.NODE_ENV !== 'production') {
    middlewares.push(createLogger());
  }
  return createStore(
    counter,
    applyMiddleware(...middlewares)
  );
};
const store = configureStore();

// functional component
let Counter = ({
  currCounter,
  onIncrement,
  onDecrement
}) => (
  <div>
    <h1>{currCounter}</h1>
    <button onClick={onIncrement}>+</button>
    <button onClick={onDecrement}>-</button>
  </div>
);

// Connect logic
const mapStateToProps = (state) => ({
  currCounter: state
})
const mapDispatchToProps = {
  onIncrement: () =>
    store.dispatch({
      type: 'INCREMENT'
    }),
  onDecrement: () =>
    store.dispatch({
      type: 'DECREMENT'
    }),
}
Counter = connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

// Entry point
const render = () => {
  ReactDOM.render(
    <Provider store={store}>
      <Counter />
    </Provider>,
    document.getElementById('root')
  );
};

store.subscribe(render);
render();
Run Code Online (Sandbox Code Playgroud)

双重作用

els*_*syr 6

您收到重复分派的原因是因为您编写mapDispatchToProps对象的方式(以及看似无害的双箭头语法使用)。

没有大括号的双箭头语法,如 in () => value,转换为function { return value }.

因此,onIncrement实际上不再是一个看起来像的函数{ store.dispatch(...) }——它实际上是调度调用的返回值。在这种情况下,这只是调度的操作。

如果我们写成onIncrement这样(它只返回动作对象):

onIncrement: () => {
    return {
      type: "INCREMENT"
    }
}
Run Code Online (Sandbox Code Playgroud)

我们最终会在按钮按下时正确调度动作。

这导致您的双重调度 -onIncrement首先调用store.dispatch然后从返回的对象中旋转另一个调度。

无论如何,您可以通过在您的onIncrement(): 中添加大括号来解决这个问题:

onIncrement: () => {
    store.dispatch({
      type: 'INCREMENT'
    });
},
Run Code Online (Sandbox Code Playgroud)

您也可以简单地仅返回操作对象,如前面所示。