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

Redux通讯录应用:状态更新后触发批准dispatch的优化咨询

Redux: Do I need async middleware for client-side validation without server calls?

Problem Description

I'm building a contact list app with Redux, which has two core states: the main contact list state, and the contact state in edit mode. After a user finishes editing, I need to validate the edited values and update the original state.

I ran into an issue where I needed to trigger the dispatch of an approval action after the new user input updates the state. I tried adding a function in mapDispatchToProps and calling it via ownProps.func(), but it wasn't recognized. If I put the validation logic inside the approval edit function, I couldn't get the updated state.

My current implementation works, but I think the isEditApprove function can be optimized. My question is: Do I need to use async middleware even if there are no server calls?

Current Implementation Code

Validation & Dispatch Mapping

const isEditApprove = (dispatch, ownProps) => { 
  let EditApprove = true; 
  if (!ownProps.phone || ownProps.phone.length > 12 || ownProps.phone.length < 9) { 
    dispatch(rejectEdit(ownProps.id, 'phone')); 
    EditApprove = false; 
  } 
  if (!ownProps.name || ownProps.name.trim().indexOf(' ') === -1) { 
    dispatch(rejectEdit(ownProps.id, 'name')); 
    EditApprove = false; 
  } 
  return EditApprove; 
};

const mapStateToProps = () => ({});

const mapDispatchToProps = (dispatch, ownProps) => ({
  addUserHandler() { 
    if (isEditApprove(dispatch, ownProps)) { 
      dispatch(toggleAddUserMode(ownProps.addUserMode)); 
    } 
  },
  editUserHandler(event) { 
    dispatch(changeUserInfo(ownProps.id, event.target.name, event.target.value)); 
  },
  approveEditHandler() { 
    if (isEditApprove(dispatch, ownProps)) { 
      dispatch(approveEdit(ownProps.id, ownProps.phone, ownProps.name)); 
      dispatch(toggleEditMode(ownProps.id, ownProps.name, ownProps.phone, ownProps.editMode)); 
    } 
  },
});

Action Definitions

export function toggleEditMode(id, name, phone, editMode) { 
  return { 
    "type": TOGGLE_EDIT_MODE, 
    "payload": { name, phone, id, "editMode": !editMode }, 
  }; 
}

export function approveEdit(id, phone, name) { 
  return { 
    "type": APPROVE_EDIT, 
    "payload": { id, phone, name } 
  }; 
}

export function rejectEdit(id, errorType) { 
  let errorMessage; 
  switch (errorType) { 
    case 'phone': 
      errorMessage = 'The phone number must be between 9 and 12 characters'; 
      break; 
    case 'name': 
      errorMessage = 'The name must contain two words'; 
      break; 
    default: 
      errorMessage = 'Unknown error'; 
  } 
  return { 
    "type": REJECT_EDIT, 
    "payload": { id, errorType, errorMessage } 
  }; 
}

Answer

Great question! The short answer is: No, you don't need async middleware for this scenario. Async middleware like Redux Thunk or Saga is only necessary when you have asynchronous operations (like API calls, timers, or any logic that doesn't resolve immediately). Your client-side validation is entirely synchronous, so Redux's default dispatch mechanism works perfectly here.

That said, your current isEditApprove function does mix validation logic with Redux dispatch calls, which makes it tightly coupled to Redux and harder to test independently. Here's a cleaner, more maintainable way to refactor this:

Step 1: Extract Validation into a Pure Function

First, separate the validation logic from dispatch. Pure functions are easier to test and reuse:

// Pure validation function - no Redux dependencies
const validateContactInput = (name, phone) => {
  const invalidFields = [];
  
  if (!phone || phone.length < 9 || phone.length > 12) {
    invalidFields.push('phone');
  }
  
  if (!name || name.trim().indexOf(' ') === -1) {
    invalidFields.push('name');
  }
  
  return invalidFields;
};

Step 2: Use the Validator in Your Dispatch Handlers

Now, use this pure function in your mapDispatchToProps handlers to decide which actions to dispatch:

const mapDispatchToProps = (dispatch, ownProps) => ({
  addUserHandler() {
    const invalidFields = validateContactInput(ownProps.name, ownProps.phone);
    
    if (invalidFields.length === 0) {
      dispatch(toggleAddUserMode(ownProps.addUserMode));
    } else {
      // Dispatch rejection actions for all invalid fields
      invalidFields.forEach(field => dispatch(rejectEdit(ownProps.id, field)));
    }
  },
  editUserHandler(event) {
    dispatch(changeUserInfo(ownProps.id, event.target.name, event.target.value));
  },
  approveEditHandler() {
    const invalidFields = validateContactInput(ownProps.name, ownProps.phone);
    
    if (invalidFields.length === 0) {
      dispatch(approveEdit(ownProps.id, ownProps.phone, ownProps.name));
      dispatch(toggleEditMode(ownProps.id, ownProps.name, ownProps.phone, ownProps.editMode));
    } else {
      invalidFields.forEach(field => dispatch(rejectEdit(ownProps.id, field)));
    }
  },
});

Why This Is Better

  • Decoupling: The validation logic is now independent of Redux, so you can test it without needing to mock dispatch or Redux store.
  • Clarity: Each handler's logic is explicit—you can see exactly when we trigger success actions vs. error actions.
  • Maintainability: If you need to adjust validation rules later, you only have to change one place (the pure function) instead of hunting through dispatch handlers.

Again, save async middleware for when you actually need to handle asynchronous work. For pure client-side sync validation, this refactored approach is simpler and cleaner.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:58:12