如何创建两个可重用的调用自定义钩子?

时间:2021-05-11 09:35:56

标签: javascript reactjs react-hooks

我创建了一些可在任何地方重用代码的逻辑。我有一个用于处理输入元素的 input.jsx 组件和用于管理所有内容的 use-form.js 自定义钩子,我有一个用于创建表单逻辑的基本表单组件。在基本表单组件中,我多次调用自定义钩子。这很乏味而且相当重复*所以我想在 input.jsx 组件中创建两个可重用的调用自定义钩子

input.component.jsx

const Input = (props) => {

return (
<div className={`form-control ${props.error && 'invalid'}`}>
  <label htmlFor={props.id}>{props.label}</label>
  <input
    type={props.type}
    id={props.id}
    value={props.value}
    onChange={props.changeHandler}
    onBlur={props.blurHandler}
  />
  {props.error && <p className="error-text">{props.label} must be entered!</p>}
</div>


 );
};

使用-input.js

import { useReducer } from 'react';

const inputReducer = (state, action) => {
  switch (action.type) {
    case 'INPUT':
      return { value: action.value, isTouched: state.isTouched };
    case 'BLUR':
      return { isTouched: true, value: state.value };
    case 'RESET':
      return { value: '', isTouched: false };
  }
  return state;
};

export const useInput = (validateValue) => {
  const [state, dispatch] = useReducer(inputReducer, {
    value: '',
    isTouched: false,
  });

  const valueIsValid = validateValue(state.value);
  const error = !valueIsValid && state.isTouched;

  const valueChangeHandler = (e) => {
    dispatch({ type: 'INPUT', value: e.target.value });
  };

  const inputBlurHandler = () => {
    dispatch({ type: 'BLUR' });
  };

  const reset = () => {
    dispatch({ type: 'RESET' });
  };

  return {
    value: state.value,
    isValid: valueIsValid,
    error,
    valueChangeHandler,
    inputBlurHandler,
    reset,
  };
};

basic-form.component.jsx

import { useInput } from '../hooks/use-input';
import Input from './input.component';

const BasicForm = () => {
  const {
    value: name,
    isValid: nameIsValid,
    error: nameHasError,
    valueChangeHandler: nameChangeHandler,
    inputBlurHandler: nameBlurHandler,
    reset: nameReset,
  } = useInput((value) => value.trim() !== '');

  const {
    value: surname,
    isValid: surnameIsValid,
    error: surnameHasError,
    valueChangeHandler: surnameChangeHandler,
    inputBlurHandler: surnameBlurHandler,
    reset: surnameReset,
  } = useInput((value) => value.trim() !== '');

  const {
    value: email,
    isValid: emailIsValid,
    error: emailHasError,
    valueChangeHandler: emailChangeHandler,
    inputBlurHandler: emailBlurHandler,
    reset: emailReset,
  } = useInput((value) => /^\S+@\S+\.\S+$/.test(value));

  let formIsValid = false;

  if (nameIsValid && surnameIsValid && emailIsValid) {
    formIsValid = true;
  }

  const formSubmitHandler = (e) => {
    e.preventDefault();
    nameReset();
    surnameReset();
    emailReset();
  };

  return (
    <form onSubmit={formSubmitHandler}>
      <div className="control-group">
        <Input
          id="name"
          label="First Name"
          type="text"
          error={nameHasError}
          value={name}
          changeHandler={nameChangeHandler}
          blurHandler={nameBlurHandler}
        />
        <Input
          id="surname"
          label="Last Name"
          type="text"
          error={surnameHasError}
          value={surname}
          changeHandler={surnameChangeHandler}
          blurHandler={surnameBlurHandler}
        />
        <Input
          id="email"
          label="Email"
          type="email"
          error={emailHasError}
          value={email}
          changeHandler={emailChangeHandler}
          blurHandler={emailBlurHandler}
        />
      </div>
      <div className="form-actions">
        <button disabled={!formIsValid}>Submit</button>
      </div>
    </form>
  );
};

export default BasicForm;

问题是我们必须从 input.jsx 返回两个值到 basic-form.jsx。第一个显示属性 isValid 与否。其次,一个函数,用于重置每个单独的输入元素。此外,我们必须接收一个函数来验证从父组件到子组件的逻辑。我们如何解决这个问题?我认为我们应该使用 useRefuseImperativeHandleforwardRef 但如何使用?

请投票让更多人看到。

0 个答案:

没有答案