反应还原中的形式状态

时间:2017-06-12 14:40:05

标签: reactjs ecmascript-6 redux create-react-app react-redux-form

我是React生态系统的初学者,我正在使用React中的表单,构建一个包含两个字段的登录表单 - 电子邮件和密码。

我在redux中维护我的整个表单状态。例如:

const defaultState = { 
    touched: { email: false, password: false },
    loginFormErrors: {email: '', password: ''},
    emailValid: false,
    passwordValid: false,
    formValid: false
}

其中一些状态值由validateLoginFields(reducer)更新,在调度VALIDATE_LOGIN_FIELDS操作时会调用它们

const validateLoginFields = (state, action) => {
  const newLoginFormErrors = {}
  let emailValid = state.emailValid
  let passwordValid = state.passwordValid
  let formValid = state.formValid

  switch(action.key) {
    case 'email':
    if(!action.value){
        emailValid = false
        newLoginFormErrors.email = ''
    }else{
        const pattern = new RegExp("[^\\s@]+@[^@\\s]+\\.[^@\\s]+")
        emailValid = pattern.test(action.value)
        newLoginFormErrors.email = emailValid ? '' : 'Invalid email'
    }
    break
    case 'password':
    if(!action.value){
        passwordValid = false
        newLoginFormErrors.password = ''
    }else{
        passwordValid = action.value.length >= 6
        newLoginFormErrors.password = passwordValid ? '': 'Password is too short!';
    }
    break
    default:
    break
  }

  formValid = emailValid && passwordValid
  const loginFormErrorData = {}
  Object.assign(loginFormErrorData, state.loginFormErrors, newLoginFormErrors)
  const newState = {}
  Object.assign(newState, state, { loginFormErrors: loginFormErrorData, emailValid: emailValid, passwordValid: passwordValid, formValid: formValid })
  return newState
}

我在这里几乎没有问题:

  1. 我是否通过在Redux中维护我的表单的客户端验证详细信息(例如有效,触摸,formErrors等)来做正确的事情,或者我最好为此目的使用本地状态?由于我还在redux中存储auth相关数据,因此我觉得让Redux成为我所有事物的唯一真实来源感觉更舒服一点,但仍然希望与社区的其他人一起验证这个想法。

  2. 是否可以像validateLoginFields这样的reducer函数执行客户端验证,就像我在我的示例中所示?它确实返回一个新的状态 - 这是reducer的功能,但是这个函数也在为我执行验证...我觉得这里有问题,可以用更好的方式完成。我的意思是更通用的验证? reducer是否适合进行验证?

  3. 到目前为止,我正在努力进行客户端验证,似乎无法弄清楚如何以通用方式构建验证器,以便在应用程序变大时我可以扩展它。非常感谢社区对此的任何想法。

    我确实尝试使用Redux-form和React-redux-form,这些库很棒,但我现在只想自己执行这些验证以用于学习目的。

    更新:

    我将actionCreator改为看起来像这样,而不是在reducer中进行所有验证。我似乎无法弄清楚我应该在哪里以及如何以共享方式获得我的验证,以便我的应用程序中的其他电子邮件和密码字段可以访问此逻辑,而不仅仅是登录组件。

    export function validateLoginFields(key, value) {
      const newLoginFormErrors = {}
      let emailValid = false
      let passwordValid = false
      let formValid = false
    
      switch(key) {
        case 'email':
        if(!value){
          emailValid = false
          newLoginFormErrors.email = ''
        }else{
          const pattern = new RegExp("[^\\s@]+@[^@\\s]+\\.[^@\\s]+")
          emailValid = pattern.test(value)
          newLoginFormErrors.email = emailValid ? '' : 'Invalid email'
        }
        break
        case 'password':
        if(!value){
          passwordValid = false
          newLoginFormErrors.password = ''
        }else{
          passwordValid = value.length >= 6
          newLoginFormErrors.password = passwordValid ? '': 'Password is too short!';
        }
        break
        default:
        break
      }
    
      formValid = emailValid && passwordValid
    
      return { type: VALIDATE_LOGIN_FIELDS, newLoginFormErrors, emailValid, passwordValid, formValid }
    }
    

    通过上述更改,即使我正在验证密码字段,我也将自己置于另一个问题,即我将返回emailValid=false。如果在我之前的状态emailValid=true中,那么它就变为假。发生这种情况是因为我覆盖了我的状态值。有什么办法可以在actionCreator中访问当前状态,这样如果什么都没有改变,我可以返回相同的状态值吗?

    但是,根据这篇帖子,在actionCreator中访问状态并不是最好的方式..

    Accessing Redux state in an action creator?

1 个答案:

答案 0 :(得分:1)

我将我的验证放在我的Reducer中。减速器采用先前的状态和动作,然后返回一个新的状态。

这是一个简单商店的结构:

{customer: {
  firstName: "FatBoy",
  lastName: "Slim",
  email: 'foo@bar.com',
  validationErrors: {}
}}

这是一个更新客户并验证电子邮件地址的reducer:

function customerReducer(state = {}, action) {
   switch (action.type) {
     case 'UPDATE_CUSTOMER':
       let validationErrors = {}
       let emailError = validateEmail(action.customer.email);
       if (emailError) {
         validationErrors['email'] = emailError;
       }   
       return {...state, ...action.customer, validationErrors};
     default:
       return state;
   }
}

(注意:这是伪代码。它从来没有被任何人运行过。它可以帮助你获得要点。)

对我来说,reducer是进行验证的合理位置。他们认为,动作创建者的工作是发送更新商店所需的最小状态,而减速器的工作是将该状态转换为最优应用程序需要的状态。我是那种认为验证是最佳的人,所以我在减速器中这样做。