首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >支持回调,以便在使用React窗体验证时更改另一个字段值

支持回调,以便在使用React窗体验证时更改另一个字段值
EN

Stack Overflow用户
提问于 2020-12-02 00:20:16
回答 1查看 5.5K关注 0票数 3

TL;DR

这工作:https://codesandbox.io/s/stoic-beaver-ucydi

使用refactor表单重构后,此操作不起作用:https://codesandbox.io/s/objective-cloud-bkunr?file=/src/ControlledTextField.tsx

长话短说

没有反应钩形式(工作确定)

最近,我使用Fluent UI和自定义组件中的包装字段构建了一个有状态的React表单。

我包含了一个特性,在输入Site字段时生成Site字段中的值(在我的示例中,它只是复制字段值并删除URL无效的字符)。

(简化的)代码运行良好,如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
import * as React from 'react';
import {useState} from 'react';
import { PrimaryButton } from 'office-ui-fabric-react';
import SiteTitleField from '../../../common/formFields/SiteTitleField';
import SiteUrlField from '../../../common/formFields/SiteUrlField';

export default function MyForm(props) {

  const urlPrefix: string = "https://" + window.location.hostname + "/sites/";

  const [siteTitle, setSiteTitle] = useState();
  const [titleErrorMessage, setTitleErrorMessage] = useState('');

  const [siteUrl, setsiteUrl] = useState();
  const [urlErrorMessage, setUrlErrorMessage] = useState('');

  function handleTitleChange(e) {
    if (e.target.value.length) {
      setTitleErrorMessage('');
    } else {
      setTitleErrorMessage('This field is required.');
    }
    setSiteTitle(e.target.value);
    setsiteUrl(e.target.value.replace(/[^A-Za-z0-9_-]/g, ""));
  }
  
  function handleUrlChange(e) {
    if (e.target.value.length) {
      setUrlErrorMessage('');
    } else {
      setUrlErrorMessage('This field is required.');
    }
    setsiteUrl(e.target.value);
  }
  
  function handleButtonClick(e) {
    // call to API
  }

  return (
    <SiteTitleField
      siteTitle={siteTitle}
      titleErrorMessage={titleErrorMessage}
      handleTitleChange={handleTitleChange}
    />

    <SiteUrlField
      siteUrl={siteUrl}
      urlErrorMessage={urlErrorMessage}
      urlPrefix={urlPrefix}
      handleUrlChange={handleUrlChange}
    />

    <PrimaryButton 
      text="Create a Request" 
      onClick={handleButtonClick}
    />
  );
}

SiteTitleField组件:

代码语言:javascript
代码运行次数:0
运行
复制
import * as React from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';

export default function SiteTitleField(props) {
  return (
    <TextField 
      value={props.siteTitle}
      required 
      aria-required="true"
      errorMessage={props.titleErrorMessage}
      label="Site Title" 
      placeholder="Set the title of the site"
      onChange={props.handleTitleChange}
    />
  );
}

SiteUrlField组件:

代码语言:javascript
代码运行次数:0
运行
复制
import * as React from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';

export default function SiteUrlField(props) {
  return (
    <TextField
      value={props.siteUrl}
      required
      aria-required="true"
      errorMessage={props.urlErrorMessage}
      label="Site URL"
      prefix={props.urlPrefix}
      placeholder="Set site URL alias"
      onChange={props.handleUrlChange}
    />
  );
}

使用React形式(工作不正常)

现在,我正在尝试使用refactor表单和Yup验证模式重构我的表单。

我使用组件及其呈现属性包装了Fluent UI TextField组件:

代码语言:javascript
代码运行次数:0
运行
复制
import * as React from 'react';
import { Control, Controller, FieldErrors } from "react-hook-form";
import { TextField } from 'office-ui-fabric-react';

export interface IControlledTextFieldProps {
    control: Control<any>;
    name: string;
    errors: FieldErrors<any>;
    label?: string;
    prefix?: string;
    placeholder?: string;

    onChangeCallback?: (...event: any[]) => void;
    refValue?: string;
}
  
export const ControlledTextField: React.FC<IControlledTextFieldProps> = ({
  control,
  name,
  errors,
  label,
  prefix, 
  placeholder,

  onChangeCallback,
  refValue,

}) => {
  return (
    <Controller
      name={name}
      control={control}
      disabled={disabled}
      render={({ onChange, onBlur, value, name: fieldName }) => (
        <TextField

          onChange={(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {onChange(refValue); onChangeCallback && onChangeCallback(event);}}
          value={refValue}

          onBlur={onBlur}
          name={fieldName}
          errorMessage={errors[fieldName] && errors[fieldName].message}
          label={label}
          prefix={prefix}
          placeholder={placeholder}
        />
      )}
    />
  );
};

我相应地替换了SiteTitleField和SiteUrlField的代码,并添加了一个简单的Yup验证模式:

代码语言:javascript
代码运行次数:0
运行
复制
const schema = yup.object().shape({
  siteTitle: yup.string().required("Site Title needs to be provided."),
  siteUrl: yup.string().required("Site URL needs to be provided."),
});

const { handleSubmit, errors, control } = useForm<Inputs>({
  resolver: yupResolver(schema)
});

我用<form>标记包装了表单,并相应地更改了字段属性:

代码语言:javascript
代码运行次数:0
运行
复制
<form onSubmit={handleSubmit(handleButtonClick)}>
    <SiteTitleField
      name="siteTitle"
      control={control}
      errors={errors}
      handleTitleChange={handleTitleChange}
    />
    
    <SiteUrlField
      name="siteUrl"
      control={control}
      errors={errors}
      siteUrl={siteUrl}
      urlPrefix={urlPrefix}
    />
        
    <PrimaryButton 
      text="Create a Request" 
      type="submit"
    />
</form>

关于状态,我只留下了值复制所需的东西:

代码语言:javascript
代码运行次数:0
运行
复制
  const [siteUrl, setsiteUrl] = useState();
  
  function handleTitleChange(e) {
    setsiteUrl(e.target.value.replace(/[^A-Za-z0-9_-]/g, ""));
  }

问题

我不能让React表单验证和我的值复制功能同时工作。

如果使用以下代码,验证效果很好,但用户无法编辑站点URL字段:

代码语言:javascript
代码运行次数:0
运行
复制
onChange={(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {onChange(refValue); onChangeCallback && onChangeCallback(event);}}
value={refValue}

或者复制和编辑字段值很好,但是即使输入了值,验证也表明这两个字段都是空的(必需),当使用以下代码时:

代码语言:javascript
代码运行次数:0
运行
复制
onChange={onChangeCallback}
value={refValue}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-02 03:36:12

好吧,我想出来了。

而不是使用状态更新字段值。

代码语言:javascript
代码运行次数:0
运行
复制
  const [siteUrl, setsiteUrl] = useState();
  
  function handleTitleChange(e) {
    setsiteUrl(e.target.value.replace(/[^A-Za-z0-9_-]/g, ""));
  }

我应该使用useFormsetValue

代码语言:javascript
代码运行次数:0
运行
复制
  const { 
    handleSubmit, 
    errors, 
    control, 
    setValue // added
  } = 
  useForm<Inputs>({
    resolver: yupResolver(schema)
  });

  function handleTitleChange(e) {
    // changed:
    setValue("siteUrl", e.target.value.replace(/[^A-Za-z0-9_-]/g, ""), {
      shouldValidate: true
    });
  }

value in ControlledTextField应该简单地解析为:

代码语言:javascript
代码运行次数:0
运行
复制
value={value}

工作解决方案:https://codesandbox.io/s/focused-montalcini-ehbp3?file=/src/App.tsx

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65100499

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档