Search code examples
reactjseventsnestedreact-hooksonchange

How do I trigger an event function nested in another event function on React?


I am trying to find an efficient way to write functions without creating duplicates like this.

const InputChange = (initialValue, validateInputChange = false, validate) => {

  const handleInputChange = (event) => {
    const { name, value } = event.target; // <- Target Name and Value
    setValues({
      ...values,
      [name]: value,
    });
  };

  const handleValidation = (event) => {
    const { name, value } = event.target; // <- Same Target Name and Value
    if (validateInputChange) {
      validate({ [name]: value });
    }
  };

  return {
    values,
    setValues,
    handleInputChange,
    errors,
    setErrors,
    handleValidation,
  };

};

What I am trying to accomplish is stacking these two functions without having to pass the same target name and value twice, like this.

  const handleInputChange = (event) => {
    const { name, value } = event.target; // <- Target Name and Value Passed Once
    setValues({
      ...values,
      [name]: value,
    });
    const handleValidation = (event) => {
      if (validateInputChange) {
        validate({ [name]: value });
      }
    };
  };

How I am triggering these event: onChange={ handleInputChange } and onBlur={ handleValidation }

<TextField
   name="name"
   label="Name"
   value={values.name}
   onChange={handleInputChange}
   onBlur={handleValidation} // <- This is not working: onBlur={handleInputChange(handleValidation)}?
   error={errors.name}
 />

How do I trigger an event function nested in another event function on React?


Solution

  • You can create a curried helper function that accepts an event handler, and prepares the data for it.

    The handleEventValue is a curried utility function, that accepts a handler, and returns a function that accepts and event object. It then invokes the handler, and passed it the prepare { [name]: value } object. You should define this function outside of your component / custom hook.

    const handleEventValue = handler => ({ target: { name, value } }) => handler({ [name]: value });
    

    Usage:

    const handleInputChange = handleEventValue(val => {
      setValues({
        ...values,
        ...val
      });
    });
    
    const handleValidation = handleEventValue(val => {
      if (validateInputChange) {
        validate(val);
      }
    });
    

    Example:

    const handleEventValue = handler => ({ target: { name, value } }) => handler({ [name]: value });
    
    const Example = () => {
      const [values, setValues] = React.useState({ x: '', y: '' });
      
      const handleInputChange = handleEventValue(val => {
        setValues({
          ...values,
          ...val
        });
      });
    
      return (
        <div>
          <input name="x" value={values.x} onChange={handleInputChange} />
          
          <input name="y" value={values.y} onChange={handleInputChange} />
          
          <div>x: {values.x} y: {values.y}</div>
        </div>
      );
    }
    
    ReactDOM.render(
      <Example />,
      root
    );
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    
    <div id="root"></div>