You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux常见场景实践:如何优雅实现两个Reducer值的交换

Great question! I totally get why dispatching two separate actions feels clunky here—you’re breaking a single logical operation (swapping the two names) into two disconnected steps, which not only forces you to pass around values manually but also risks inconsistencies if something goes wrong mid-process. Let’s go through a few cleaner, more maintainable approaches.

Option 1: Handle the swap via a root reducer with a single action

Since your root reducer has access to the entire app state, it can coordinate the swap operation without requiring you to pass values through action payloads manually. Here’s how it works:

First, update your child reducers to respond to a SWAP_NAMES action:

// Boy reducer
const boyReducer = (state = "Tom", action) => {
  switch(action.type) {
    case "BOY_EDIT":
      return action.value;
    case "SWAP_NAMES":
      return action.payload.newBoyName;
    default:
      return state;
  }
};

// Girl reducer
const girlReducer = (state = "Mary", action) => {
  switch(action.type) {
    case "GIRL_EDIT":
      return action.value;
    case "SWAP_NAMES":
      return action.payload.newGirlName;
    default:
      return state;
  }
};

Then, modify your root reducer to orchestrate the swap when it receives the SWAP_NAMES action:

const rootReducer = (state, action) => {
  if (action.type === "SWAP_NAMES") {
    // Grab current values from the full state
    const currentBoy = state.boy;
    const currentGirl = state.girl;
    
    // Pass swapped values to each child reducer
    return {
      boy: boyReducer(state.boy, {
        type: "SWAP_NAMES",
        payload: { newBoyName: currentGirl }
      }),
      girl: girlReducer(state.girl, {
        type: "SWAP_NAMES",
        payload: { newGirlName: currentBoy }
      })
    };
  }

  // Delegate all other actions to child reducers as usual
  return {
    boy: boyReducer(state.boy, action),
    girl: girlReducer(state.girl, action)
  };
};

To trigger the swap, you only need to dispatch one action:

dispatch({ type: "SWAP_NAMES" });

This keeps the swap operation atomic—either both values update, or neither does—eliminating consistency risks.

Redux Toolkit (RTK) simplifies cross-slice operations and reduces boilerplate. There are two sub-options here, depending on whether you want to keep boy and girl as separate slices.

Sub-option 2a: Keep separate slices with a thunk action

RTK’s thunks let you access the current state before dispatching an action, so you can grab the current names and pass them in a single swap action:

import { createSlice, configureStore, createAsyncThunk } from '@reduxjs/toolkit';

// Create boy slice
const boySlice = createSlice({
  name: 'boy',
  initialState: 'Tom',
  reducers: {
    editBoy: (state, action) => action.payload
  },
  extraReducers: (builder) => {
    builder.addCase(swapNames.fulfilled, (state, action) => {
      return action.payload.newBoyName;
    });
  }
});

// Create girl slice
const girlSlice = createSlice({
  name: 'girl',
  initialState: 'Mary',
  reducers: {
    editGirl: (state, action) => action.payload
  },
  extraReducers: (builder) => {
    builder.addCase(swapNames.fulfilled, (state, action) => {
      return action.payload.newGirlName;
    });
  }
});

// Define thunk to handle swap
export const swapNames = createAsyncThunk(
  'names/swap',
  async (_, { getState }) => {
    const { boy, girl } = getState();
    return { newBoyName: girl, newGirlName: boy };
  }
);

// Configure store
const store = configureStore({
  reducer: {
    boy: boySlice.reducer,
    girl: girlSlice.reducer
  }
});

To trigger the swap, just dispatch the thunk:

dispatch(swapNames());

If boy and girl are part of the same logical feature (like a pair of users, a couple, etc.), merging them into a single slice eliminates cross-reducer coordination entirely:

import { createSlice, configureStore } from '@reduxjs/toolkit';

const namesSlice = createSlice({
  name: 'names',
  initialState: { boy: 'Tom', girl: 'Mary' },
  reducers: {
    editBoy: (state, action) => {
      state.boy = action.payload;
    },
    editGirl: (state, action) => {
      state.girl = action.payload;
    },
    swapNames: (state) => {
      // Swap values directly in the slice
      const temp = state.boy;
      state.boy = state.girl;
      state.girl = temp;
    }
  }
});

export const { editBoy, editGirl, swapNames } = namesSlice.actions;

const store = configureStore({
  reducer: { names: namesSlice.reducer }
});

Now swapping is as simple as:

dispatch(swapNames());

Final Takeaways

  • If boy and girl belong to the same logical domain, merging them into one slice is the cleanest, most maintainable solution.
  • If you need to keep them separate, using a root reducer handler or RTK thunk ensures your swap operation is atomic and avoids manual value passing.

内容的提问来源于stack exchange,提问作者Samuel Wong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:47:08