es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

El uso del custom hook en React siempre invoca a la función.

He creado un hook personalizado en el cual una de las variables de estado obtiene el valor inicial de una función (ver el ejemplo a continuación). Cuando hago referencia al valor, se llama a la función y se devuelve el valor devuelto por la función en lugar del último valor almacenado.

En el ejemplo a continuación, el valor inicial de touched es el valor devuelto por la función createDefaultValue. En handleOnBlur, estoy actualizando el valor de touched. Cada vez que llamo a esta función, obtengo el valor predeterminado para touched en lugar del último objeto actualizado.

const useForm = ({ initialValues = {} }) => {
  const createDefaultValues = (defaultValue) =>
    Object.keys(initialValues).reduce((obj, key) => {
      obj[key] = defaultValue;
      return obj;
    }, {});

  const [touched, setTouched] = React.useState(createDefaultValues(false));

  React.useEffect(() => {
    console.log(touched);
  }, [touched]);

  const handleOnBlur = async (e) => {
    const { name } = e.target;
    setTouched({ ...touched, [name]: true });
  };

  return { touched, handleOnBlur };
}

export default useForm;

Uso: en el archivo form.tsx

import useForm from './useForm';

const Form = (props) => {
  const { touched, handleOnBlur } = useForm({
    initialValues: { name: null, email: null }
  });

  return (
    <>
      <textfield id="name" helpertext="{touched.name" 'debe="" ser="" válido'="" :="" ''}="" error="{touched.name}" onblur="{handleOnBlur}" onchange="{..}" value="{..}"></textfield>
      <textfield id="email" helpertext="{touched.email" 'debe="" ser="" válido'="" :="" ''}="" error="{touched.email}" onblur="{handleOnBlur}" onchange="{..}" value="{..}"></textfield>

  )
}

export default Form;
Tags:  ,

Answer

  1. Avatar for davy.ai

    El problema que estás enfrentando se debe a que la función createDefaultValues se llama cada vez que se vuelve a renderizar el componente, y por lo tanto, el valor inicial de touched se sobrescribe con los valores predeterminados devueltos por la función. Para solucionar este problema, puedes envolver la función createDefaultValues dentro del hook React.useMemo, que solo se llamará una vez durante el renderizado inicial y devolverá el valor en caché para renderizados posteriores.

    Aquí tienes una implementación actualizada del hook personalizado useForm:

    const useForm = ({ initialValues = {} }) => {
      const createDefaultValues = useMemo(
        () =>
          Object.keys(initialValues).reduce((obj, key) => {
            obj[key] = false;
            return obj;
          }, {}),
        [initialValues]
      );
    
      const [touched, setTouched] = useState(createDefaultValues);
    
      useEffect(() => {
        console.log(touched);
      }, [touched]);
    
      const handleOnBlur = async (e) => {
        const { name } = e.target;
        setTouched((prevTouched) => ({ ...prevTouched, [name]: true }));
      };
    
      return { touched, handleOnBlur };
    };
    
    export default useForm;
    

    Observa cómo la función createDefaultValues está envuelta en el hook useMemo, que utiliza initialValues como su dependencia. Esto asegura que la función solo se llame una vez durante el renderizado inicial y que se devuelva el valor en caché para renderizados posteriores.

    Además, la función setTouched se actualiza para usar la forma funcional que toma el estado anterior como argumento y devuelve el estado actualizado. Esto asegura que el estado touched anterior no se sobrescriba y que el nuevo valor se mezcle con el estado anterior.

Comments are closed.