有没有办法在 redux 中重用 reducer 逻辑?

Is there a way to reuse a reducer logic in redux?

我正在使用 react/redux 构建我的应用程序。有多个按钮,应用程序需要跟踪这些按钮是否被单击的状态。这些按钮都使用相同的 reducer 逻辑,即在单击按钮时将状态从 true 切换为 false。唯一的区别是州的名称。有没有办法通过定义一个可以应用于多个状态的“全局”reducer 来减少我的代码?请参考此图片以获得 example

谢谢!

这就是我要做的。而不是为每个按钮类型(如 MENU_BTNSEARCH_BTN 等)调度独特的操作。我会调度 { type: 'TOGGLE_BUTTON', payload: 'menu' } 并在 reducer

case TOGGLE_BUTTON:
  return {
    [payload]: !state[payload]
    ...state
  }

然后您可以像这样切换按钮

const toggleButton = key => ({
  type: 'TOGGLE_BUTTON',
  payload: key
})
dispatch(toggleButton('menu'))
dispatch(toggleButton('search'))

这样您就可以跟踪任意数量的按钮。您的状态将如下所示

...
buttons: {
  menu: true,
  search: false
}
...

并且您可以轻松地为每个按钮编写选择器

// Component displaying state of menu button //
let MyComponent = ({ menuButtonState }) => (
  <div>
  Menu button is {menuButtonState ? 'on' : 'off'}
  </div>
)
// Helper function for creating selectors //
const createGetIsButtonToggledSelector = key => state => !!state.buttons[key]
// Selector getting state of a menu button from store //
const getIsMenuButtonToggled = createGetIsButtonToggledSelector('menu')
// Connecting MyComponent to menu button state //
MyComponent = connect(state => ({
  menuButtonState: getIsMenuButtonToggled(state)
})(MyComponent)

您可以创建一个通用高阶 reducer,它接受给定的 reducer 函数和名称或标识符。

function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

function createNamedWrapperReducer(reducerFunction, reducerName) {
  return (state, action) => {
    const { name } = action
    const isInitializationCall = state === undefined
    if (name !== reducerName && !isInitializationCall) return state

    return reducerFunction(state, action)
  }
}

const rootReducer = combineReducers({
  counterA: createNamedWrapperReducer(counter, 'A'),
  counterB: createNamedWrapperReducer(counter, 'B'),
  counterC: createNamedWrapperReducer(counter, 'C')
})

上面的 createdNamedWrapperReducer() 方法应该开箱即用。

有关更详细的说明或更多示例,请参阅 Redux's recipes for Reusing Reducer Logic