Link 内部反应最终形式不起作用

Link inside react final form does not work

在使用自定义错误组件的 React 最终形式中,link 之后的它不起作用。如果我使用一个简单的 span link 而不是错误组件就可以正常工作。

预期的行为是什么?

错误应该出现在下面,因为我模糊了输入 link 应该在第一次点击时打开

代码

基于https://final-form.org/docs/react-final-form/examples/record-level-validation

index.js

import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

const onSubmit = async values => {
  await sleep(300);
  window.alert(JSON.stringify(values, 0, 2));
};

const Error = ({ name }) => (
  <Field
    name={name}
    subscription={{ touched: true, error: true }}
    render={({ meta: { touched, error } }) =>
      touched && error ? <span style={{ color: "red" }}>{error}</span> : null
    }
  />
);

const App = () => (
  <Styles>
    <h1>React Final Form Example</h1>
    <h2>Password / Confirm Validation</h2>
    <a
      href="https://final-form.org/react"
      target="_blank"
      rel="noopener noreferrer"
    >
      Read Docs
    </a>
    <Form
      onSubmit={onSubmit}
      validate={values => {
        const errors = {};
        if (!values.username) {
          errors.username = "Required";
        }

        return errors;
      }}
      render={({ handleSubmit, form, submitting, pristine, values }) => (
        <form onSubmit={handleSubmit}>
          <a
            href="https://final-form.org/react"
            target="_blank"
            rel="noopener noreferrer"
          >
            [works] Down Read Docs
          </a>
          <Field name="username">
            {({ input, meta }) => (
              <div>
                <label>Username</label>
                <input
                  {...input}
                  type="text"
                  placeholder="Username"
                  autoFocus
                />
              </div>
            )}
          </Field>

          <Error name="username" />
          <a
            href="https://final-form.org/react"
            target="_blank"
            rel="noopener noreferrer"
          >
            [does not work] Read Docs
          </a>

          <div className="buttons">
            <button type="submit" disabled={submitting}>
              Submit
            </button>
            <button
              type="button"
              onClick={form.reset}
              disabled={submitting || pristine}
            >
              Reset
            </button>
          </div>
          <pre>{JSON.stringify(values, 0, 2)}</pre>
        </form>
      )}
    />
  </Styles>
);

render(<App />, document.getElementById("root"));

Styled.js

import styled, { css } from 'styled-components'

const btn = (light, dark) => css`
  white-space: nowrap;
  display: inline-block;
  border-radius: 5px;
  padding: 5px 15px;
  font-size: 16px;
  color: white;
  &:visited {
    color: white;
  }
  background-image: linear-gradient(${light}, ${dark});
  border: 1px solid ${dark};
  &:hover {
    background-image: linear-gradient(${light}, ${dark});
    &[disabled] {
      background-image: linear-gradient(${light}, ${dark});
    }
  }
  &:visited {
    color: black;
  }
  &[disabled] {
    opacity: 0.6;
    cursor: not-allowed;
  }
`

const btnDefault = css`
  ${btn('#ffffff', '#d5d5d5')} color: #555;
`

const btnPrimary = btn('#4f93ce', '#285f8f')

export default styled.div`
  font-family: sans-serif;

  h1 {
    text-align: center;
    color: #222;
  }

  h2 {
    text-align: center;
    color: #222;
  }

  & > div {
    text-align: center;
  }

  a {
    display: block;
    text-align: center;
    color: #222;
  }

  form {
    max-width: 500px;
    margin: 10px auto;
    border: 1px solid #ccc;
    padding: 20px;
    box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
    border-radius: 3px;

    & > div {
      display: flex;
      flex-flow: row nowrap;
      line-height: 2em;
      margin: 5px;
      & > label {
        color: #333;
        width: 110px;
        font-size: 1em;
        line-height: 32px;
      }
      & > input,
      & > select,
      & > textarea {
        flex: 1;
        padding: 3px 5px;
        font-size: 1em;
        margin-left: 15px;
        border: 1px solid #ccc;
        border-radius: 3px;
      }
      & > input[type='checkbox'] {
        margin-top: 7px;
      }
      & > div {
        margin-left: 16px;
        & > label {
          display: block;
          & > input {
            margin-right: 3px;
          }
        }
      }
      & > span {
        line-height: 32px;
        margin-left: 10px;
        color: #800;
        font-weight: bold;
      }
    }
    & > .buttons {
      display: flex;
      flex-flow: row nowrap;
      justify-content: center;
      margin-top: 15px;
    }
    button {
      margin: 0 10px;
      &[type='submit'] {
        ${btnPrimary};
      }
      &[type='button'] {
        ${btnDefault};
      }
    }
    pre {
      border: 1px solid #ccc;
      background: rgba(0, 0, 0, 0.1);
      box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.2);
      padding: 20px;
    }
  }
`

沙盒Link https://codesandbox.io/s/link-in-react-final-form-z2g2b?fontsize=14&hidenavigation=1&theme=dark

哇!这是一个有趣的。错误是将 link 从鼠标光标下移出,因此当您 "mouse up" 完成单击时,鼠标不再位于 hyperlink.

上方

如果您按住鼠标按钮然后在释放之前将其移动到跟随 link,则 link 将 "work"。

可以通过将错误设置为 space 来修复它是否显示,这样它就不会将页面的其余部分向下移动。

严格回答问题:

touched && error ?
    <span style={{ color: "red" }}>{error}</span> :
    <span>&nbsp;</span>

当您进出场时,这也将消除场的不断移动。

还有其他选项:

  • 将必填项放在字段末尾,就像密码字段一样
  • 仅在提交时验证
  • 将错误显示为工具提示
  • 在渲染前使用短暂的超时