1
votes

I'm building a change password component with validations. We started off using state hook functions to check the validation of the input (one upper case character, one lower case, numbers etc). This all worked fine.

Now I need to change these to default props as we want to be able to actually test the each validation in Storybook.

Some truncated code:

    type ChangePassWordModalProps = {
        ...
        isOneSpecialCharacter: boolean,
        isMinLength: boolean,
        ...
    }
    
    const defaultProps = {
        ...
        isOneSpecialCharacter: false,
        isMinLength: false,
        ...
    }
    
    const ChangePassWordModalProps = (props: ChangePassWordModalProps) => {
        const [minLength, setMinLength] = useState<boolean>(props.isMinLength);
        const [oneSpecialCharacter, setOneSpecialCharacter] = useState<boolean>(props.isOneSpecialCharacter);
        const oneSpecialCharacterRegex = new RegExp ('(?=.*[#$@!%&*?])');
    
        useEffect(() => {
          setMinLength(inputPasswordValue.length >= 12);
          setOneSpecialCharacter(oneSpecialCharacterRegex.test(inputPasswordValue));
          ...
        },[
            oneSpecialCharacterRegex,
        ]);
    
        return (
    <ul className='validation-wrapper mt-4'>
      <li
        id='specialChars'
        className={`${oneSpecialCharacter ? 'valid-password' : 'not-valid-password'}`}
      >
        1 special character
      </li>
    </ul>
  );
}

This works as the user types into the input. However if I pass in className={${props.isOneSpecialCharacter? 'valid-password' : 'not-valid-password'}}

This will work in Storybook toggling a true false button, but then the onChange function does not work.

I did look at using useState to update an object, like so:

const [oneSpecialCharacter, setOneSpecialCharacter] = useState({
    oneSpecialCharacter: false,
    props.isOneSpecialCharacter: false // this is not allowed of course
  });

As per here: https://stackoverflow.com/a/53575023/1238244

But it seems daft to have to set two booleans which are evaluating the same validation.

I also tried to use let for my useStates, like so:

let [oneSpecialCharacter, setOneSpecialCharacter] = useState<boolean>(props.isOneSpecialCharacter);

And then set oneSpecialCharacter to equal props.isOneSpecialCharacter, but no dice, let won't work for a boolean.

I can't seem to pass props values into my set functions, or inside the useEffect calls.

I did try:

useEffect(() => {
   if (inputPasswordValue.length >= 12) {
       return props.isMinLength = true;
   ... 
}

I am guessing this is a misuse of useEffect.

I will try and add a working example next and update the question, but if anyone has a bright idea please let me know.

1

1 Answers

0
votes

The reason the useEffect is not running is because you don't change oneSpecialCharacterRegex anywhere other than inside the useEffect itself. This way, that useEffect will never run again after the first render.

Try this:

useEffect(() => {
   setMinLength(inputPasswordValue.length >= 12);
          
   setOneSpecialCharacter(oneSpecialCharacterRegex.test(inputPasswordValue))     },
[inputPasswordValue] // This will make the useEffect run everytime the input is changed, thus testing your rule everytime.
);

Also, where are you getting inputPasswordValue from? Does it come from a parent? It is not in the example. In that case, just call props.inputPasswordValue