Reactjs 在React定制挂钩内进行onChange时验证输入的最佳实践?

Reactjs 在React定制挂钩内进行onChange时验证输入的最佳实践?,reactjs,react-hooks,Reactjs,React Hooks,我构建了一个定制的钩子来处理表单。我遇到的一个问题是在输入值更改时调用验证 我有四个代码片段。第二个和第三个只是为了让上下文显示完整的自定义钩子是如何实现的,但请随意跳过它们,因为我只是想知道如何实现代码段4中代码段1中的类似功能 除了在提交时调用它之外,我想这样做的原因是,如果输入值变为“”,我希望显示错误消息,当用户开始键入时,它将消失 这非常简单,当我不使用钩子时,我会在setState之后调用一个validate函数,如下所示: const validate = (name) =>

我构建了一个定制的钩子来处理表单。我遇到的一个问题是在输入值更改时调用验证

我有四个代码片段。第二个和第三个只是为了让上下文显示完整的自定义钩子是如何实现的,但请随意跳过它们,因为我只是想知道如何实现代码段4中代码段1中的类似功能

除了在提交时调用它之外,我想这样做的原因是,如果输入值变为“”,我希望显示错误消息,当用户开始键入时,它将消失

这非常简单,当我不使用钩子时,我会在setState之后调用一个validate函数,如下所示:

const validate = (name) => {
  switch(name):
    case "username":
      if(!values.username) {
        errors.username = "What's your username?";
      }
      break;
    default:
      if(!values.username) {
        errors.username = "What's your username?";
      }

      if(!values.password) {
        errors.username = "What's your password?";
      }

      break;
}

const handleChange = (e) => {
  let { name, value } = e.target; 

  this.setState({ ...values, 
    [name]: value 
  }, () => this.validate(name)) 
}
import useForm from './form.handler.js';
import validate from './form.validation.js';

const schema = { username: "", password: "" }

export default function Form() {
  const { values, errors, handleChange, handleSubmit } = useForm(schema, validate, submit);

  function submit() {
    console.log('submit:', values);
  }

  return (
    <form></form> // form stuff
  )
}
import { useState, useEffect, useCallback } from 'react';

export default function useForm(schema, validate, callback) {
  const [values, setValues] = useState(schema),
        [errors, setErrors] = useState({}),
        [loading, setLoading] = useState(false); // true when form is submitting

  useEffect(() => {
    if(Object.keys(errors).length === 0 && loading) {
        callback();
    }

    setLoading(false);
  }, [errors, loading, callback])

  // I see useCallback used for event handler's. Not part of my questions, but is it to prevent possible memory leak?
  const handleChange = (e) => {
    let { name, value } = e.target;

    setValues({ ...values, [name]: value });
  }

  const handleSubmit = (e) => {
    e.preventDefault();

    setLoading(true);
    setErrors(validate(values));
  }

  return { values, errors, handleChange, handleSubmit }
}
所以现在使用react钩子就不那么容易了。我创建了一个自定义表单处理程序,它返回值、错误、handleChange和handleSubmit。表单处理程序被传递一个initialState、validate函数和一个回调。现在看来是这样的:

const validate = (name) => {
  switch(name):
    case "username":
      if(!values.username) {
        errors.username = "What's your username?";
      }
      break;
    default:
      if(!values.username) {
        errors.username = "What's your username?";
      }

      if(!values.password) {
        errors.username = "What's your password?";
      }

      break;
}

const handleChange = (e) => {
  let { name, value } = e.target; 

  this.setState({ ...values, 
    [name]: value 
  }, () => this.validate(name)) 
}
import useForm from './form.handler.js';
import validate from './form.validation.js';

const schema = { username: "", password: "" }

export default function Form() {
  const { values, errors, handleChange, handleSubmit } = useForm(schema, validate, submit);

  function submit() {
    console.log('submit:', values);
  }

  return (
    <form></form> // form stuff
  )
}
import { useState, useEffect, useCallback } from 'react';

export default function useForm(schema, validate, callback) {
  const [values, setValues] = useState(schema),
        [errors, setErrors] = useState({}),
        [loading, setLoading] = useState(false); // true when form is submitting

  useEffect(() => {
    if(Object.keys(errors).length === 0 && loading) {
        callback();
    }

    setLoading(false);
  }, [errors, loading, callback])

  // I see useCallback used for event handler's. Not part of my questions, but is it to prevent possible memory leak?
  const handleChange = (e) => {
    let { name, value } = e.target;

    setValues({ ...values, [name]: value });
  }

  const handleSubmit = (e) => {
    e.preventDefault();

    setLoading(true);
    setErrors(validate(values));
  }

  return { values, errors, handleChange, handleSubmit }
}
这是我的表单处理程序,我正试图解决这个问题。我一直在尝试在useEffect中调用setErrors(validate(values)),但无法访问输入。我不确定,但目前,自定义挂钩如下所示:

const validate = (name) => {
  switch(name):
    case "username":
      if(!values.username) {
        errors.username = "What's your username?";
      }
      break;
    default:
      if(!values.username) {
        errors.username = "What's your username?";
      }

      if(!values.password) {
        errors.username = "What's your password?";
      }

      break;
}

const handleChange = (e) => {
  let { name, value } = e.target; 

  this.setState({ ...values, 
    [name]: value 
  }, () => this.validate(name)) 
}
import useForm from './form.handler.js';
import validate from './form.validation.js';

const schema = { username: "", password: "" }

export default function Form() {
  const { values, errors, handleChange, handleSubmit } = useForm(schema, validate, submit);

  function submit() {
    console.log('submit:', values);
  }

  return (
    <form></form> // form stuff
  )
}
import { useState, useEffect, useCallback } from 'react';

export default function useForm(schema, validate, callback) {
  const [values, setValues] = useState(schema),
        [errors, setErrors] = useState({}),
        [loading, setLoading] = useState(false); // true when form is submitting

  useEffect(() => {
    if(Object.keys(errors).length === 0 && loading) {
        callback();
    }

    setLoading(false);
  }, [errors, loading, callback])

  // I see useCallback used for event handler's. Not part of my questions, but is it to prevent possible memory leak?
  const handleChange = (e) => {
    let { name, value } = e.target;

    setValues({ ...values, [name]: value });
  }

  const handleSubmit = (e) => {
    e.preventDefault();

    setLoading(true);
    setErrors(validate(values));
  }

  return { values, errors, handleChange, handleSubmit }
}

我不确定在回调中设置状态(值)时设置其他状态(错误)是否是一个好主意,因此创建了一个

如评论所述;您可以在设置值时设置错误:

const Component = () => {
  const [values, setValues] = useState({});
  const [errors, setErrors] = useState({});
  const onChange = useCallback(
    (name, value) =>
      setValues((values) => {
        const newValues = { ...values, [name]: value };
        setErrors(validate(newValues));//set other state while in a callback
        return newValues;
      }),
    []
  );
  return <jsx />;
};
const组件=()=>{
const[values,setValues]=useState({});
const[errors,setErrors]=useState({});
const onChange=useCallback(
(名称、值)=>
设置值((值)=>{
const newValues={…values,[名称]:value};
setErrors(validate(newValues));//在回调中设置其他状态
返回新值;
}),
[]
);
返回;
};
或组合值和错误:

const Component = () => {
  const [form, setForm] = useState({
    values: {},
    errors: {},
  });
  const onChange = useCallback(
    (name, value) =>
      setForm((form) => {
        const values = { ...form.values, [name]: value };
        const errors = validate(values);
        return { values, errors };
      }),
    []
  );
  const { errors, values } = form;
  return <jsx />;
};
const组件=()=>{
const[form,setForm]=useState({
值:{},
错误:{},
});
const onChange=useCallback(
(名称、值)=>
集合形式((形式)=>{
常量值={…form.values,[name]:value};
常量错误=验证(值);
返回{值,错误};
}),
[]
);
常量{错误,值}=形式;
返回;
};

您可以在提交处理程序中有条件地调用回调:
const errors=validate(values))
then
setErrors(errors)和最后
如果(!Object.keys(errors).length){callback()}
不需要在handleChange中使用effectIn,您可以执行以下操作:
setValues((values)=>{const newValues={…values,[name]:value};setErrors(validate(newValues));return newValues;}):啊,我明白了!谢谢你给我解释清楚了。如果你想在回答中发表评论,我将接受!好主意。也许将此合并到useReducer中是更好的做法?仍然回答了我的问题,再次感谢!但有一个问题,因为这段代码会导致在其他输入上抛出错误。就像你们开始输入用户名,那个么密码就会出错,因为它还并没有值。关于一个输入的任何想法。以验证文件中的空对象开头的错误有点棘手。@Ryne您可以编写验证程序,使原始输入(未被触摸的输入)不失效
const passwordPristene=!values.hasOwnProperty('password')
values.password==未定义