使用Redux-Form V7,如何访问当前触及的字段?

时间:2017-11-14 04:55:54

标签: reactjs redux redux-form

我有一个表单(让我们称之为 LoginContainer ),其上有<Field />组件:

import { reduxForm, Field } from 'redux-form'
...
class LoginContainer extends Component {
...

render() {
  const { handleSubmit, pristine, submitting } = this.props

  return (
  ...

  <Field
    component={AuthFormInput}
    type="password"
    name="person_password"
    placeholder="Password"
  />

AuthFormInput.jsx

const AuthFormInput = ({
  input,
  name,
  placeholder,
  type,
  meta: { touched, error },
}) => {
  return [
    <div className="row-md" key={`${name}_field`}>
      <input
        placeholder={placeholder}
        name={name}
        type={type}
        className={maybeHasError}
        {...input}
      />
    </div>, // error display works amazing here, no problem
    <div key={`${name}_error`}>{touched && (error && <span className="edit_required">{error}</span>)}</div>,
  ]
}

问题是,我正在尝试处理AuthFormInput组件之外的错误,而我无法找到任何允许我从任何地方访问每个字段的touched状态的解决方案AuthFormInput以外的<Field />除外的meta.touched

我是否可以通过LoginContainer内部getTouchedFields()访问?{/ p>

Redux-Form似乎没有任何我可以使用的AuthFormInput功能。

我可以通过验证功能轻松收集当前出错的字段,但我无法找到方法来查看触摸的字段。

  

我无法找到将数据从LoginContainer传递到<Field />的方法,因为meta.touched位于它们之间,由Redux-Form内部控制。

有没有办法用Redux-Form V7做到这一点?

我有没有办法创建一个允许我在<Field />内跟踪.test{ overflow: visible; } .container { margin-top: 100px; } .word-container [tooltip-def] { display: inline-block; position: relative; } .word-container [tooltip-def]:before { left: 50%; position: absolute; transform: translateX(-50%); border-color: #323232 transparent transparent transparent; border-style: solid; border-width: 4px 6px 0 6px; content: ""; display: none; top: -6px; z-index: 99; } .word-container [tooltip-def]:after { left: 150%; position: absolute; transform: translateX(-47%); content: attr(tooltip-def); background: #323232; border-radius: 5px; color: #fff; display: none; font-family: open sans; font-size: 12px; height: auto; min-width: 250px; padding: 5px; text-align: center; top: -6px; transform: translateX(-50%) translateY(-100%); width: auto; z-index: 99; } .word-container [tooltip-def]:hover:after, .word-container [tooltip-def]:hover:before { display: inline-block; } 的HOC?

1 个答案:

答案 0 :(得分:1)

好的,我能够做到这一点,这非常非常重要。

从上述问题的代码中前进,我将其添加到LoginContainer

import withFormListener from './withFormListener'

const listeningAuthFormInput = withFormListener(AuthFormInput)

那么,<Field />成了这个:

<Field
  component={listeningAuthFormInput}
  type="password"
  name="person_password"
  placeholder="Password"
/>

HOC环绕文本输入字段(或您想要的任何字段),只需监听道具的更改,然后更新Redux:

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { updateField } from './auth_actions'

const withFormListener = function listenToFormField(FormField) {
  class WrappedField extends Component {
    handleFieldUpdate() {
      const { name } = this.props.input
      const { touched, error } = this.props.meta
      if (touched && error) {
        if (this.props[`error_${name}`] === error) return null
        return this.props.updateField({ prop: name, value: error })
      }
      if ((touched && !error) && this.props[`error_${name}`].length) {
        return this.props.updateField({ prop: name, value: '' })
      }
      return null
    }
    componentDidUpdate() {
      this.handleFieldUpdate()
    }
    render() {
      return <FormField {...this.props} />
    }
  }
  const mapStateToProps = ({
    auth: { error_person_tel, error_person_password },
  }) => ({
    error_person_tel, error_person_password,
  })
  return connect(mapStateToProps, { updateField })(WrappedField)
}

export default withFormListener

从逻辑上讲,HOC中发生的事情是:

    {li> this.propsAuthFormInput成为HOC内的this.props
  1. 收听this.props.metathis.props.input
  2. 如果触摸该字段并出现错误,请更新Redux
  3. 如果触摸该字段并且不再出现错误,请将其从Redux中删除
  4. 你应该从LoginContainer看到我的动作创建者和减速器,所以没有混淆。

    行动创作者

    export const updateField = ({ prop, value }) => ({
      type: AUTH_UPDATE_FIELD,
      payload: { prop, value },
    })
    

    <强>减速

    我建议保持状态对象平面。我在这里尝试嵌套,例如:

    const INITIAL_STATE = {
      errors: { field1, field2 }
    }
    

    但是,由于平等原因和避免覆盖errors的复杂性,它给我带来了更新状态的重大问题。它看起来比它看起来更糟糕。因此,我已经解决了这个问题:

    const INITIAL_STATE = {
      ...
      error_person_tel: '',
      error_person_password: '',
    }
    
    case AUTH_UPDATE_FIELD: {
      const { prop, value } = action.payload
      return {
        ...state,
        [`error_${prop}`]: value,
      }
    }
    

    您可以在此处详细了解规范化状态(即:展平): https://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html

    我根本没有优化它,但这是我如何显示当前的错误(在LoginContainer内):

    <ServerErrors
      errors={[
        this.props.error_person_tel,
        this.props.error_person_password,
      ].filter(val => val)}
    />
    

    这是一个简单的组件,可以呈现null或错误字符串数组。

      

    我强烈建议您使用内置的Redux-Form字段错误处理。它很棒。遗憾的是,我不得不将控件从字段级别抽象出来以完成UI设计,因此这是V7中唯一的解决方案。

    我搜索了几个星期。我提出了另一个Stack Overflow问题,它没有活动,也没有活动。我很高兴我能够找到一个有效的解决方案。

    我还强烈建议您查看Formik。我几周前在React Native中使用它来完成这个UI要求。您可能会发现它非常有效。如果您遇到任何问题,请在Twitter上与Jared Palmer对话。由于更智能的架构,Formik与Redux-Form相比具有性能提升。我对React Native感到非常满意。

    如果你冒险走这条路,要非常小心地设置由setState 引起的无限循环。我做了数小时和数小时的研究和试验。这个错误:)我对解决方案的简洁性感到满意。如果你有更好的方法,请告诉我。