Reactjs react-redux中的形式状态

Reactjs react-redux中的形式状态,reactjs,ecmascript-6,redux,create-react-app,react-redux-form,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,

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

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

const defaultState = { 
    touched: { email: false, password: false },
    loginFormErrors: {email: '', password: ''},
    emailValid: false,
    passwordValid: false,
    formValid: false
}
其中一些状态值由
validateLoginFields
(reducer)更新,在调度VALIDATE\u LOGIN\u 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
}
我这里有几个问题:

  • 我在Redux中维护表单的客户端验证详细信息(例如有效、触碰、表单错误等)是正确的做法,还是使用本地状态更好?由于我还将与auth相关的数据存储在redux中,我只是觉得redux作为我的所有事情的唯一真相来源,我感到有点舒服,但仍然想与社区其他人一起验证这个想法

  • validateLoginFields
    这样的reducer函数执行我在示例中所示的客户端验证是否合适?它确实返回了一个新的状态-这是一个reducer所做的,但是这个函数也在为我执行验证。。。我觉得这里有些地方不对劲,可以用更好的方法来做。我是说更普遍的验证?reducer是这样验证的合适地方吗

  • 到目前为止,我一直在努力进行客户端验证,似乎还不知道应该如何以一种通用的方式构造验证器,以便在我的应用程序变大时可以扩展它。我真的很感谢社区对这方面的任何想法

    我确实尝试过使用Redux表单和React Redux表单,这些库非常好,但现在我只想自己执行这些验证,以便于学习

    更新:

    我将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则变为false。这是因为我覆盖了我的状态值。是否有任何方法可以访问actionCreator中的当前状态,以便在没有任何更改的情况下返回相同的状态值

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


    我将验证放在我的还原器中。还原程序执行以前的状态和操作,然后返回新状态

    以下是一个简单商店的结构:

    {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的任务是将该状态转换为应用程序所需的最佳状态。我是那种认为验证是最优的人,所以我在我的简化程序中这样做。

    我会将验证放在actionCreator()中。通常,减缩器只是把一个新的状态作为参数,不做更多的事情。这很酷。redux表单的替代方案要复杂得多。这在我看来并不理想。验证将在对服务器的任何调用之后进行:我们将AJAX调用放在ActionCreators(异步)中,它们位于redux流中的Reducer之前——通常验证应该在任何AJAX请求之前完成。