Как скрыть / показать пароль с помощью Material UI и React Hook Forms

Извините за вопрос, может быть, это очень глупо, но я учусь и не могу его решить, я взял шаблон подписки из material-ui и решил выполнить валидацию с помощью форм реагирования, и все работает, но я хотел добавить функцию отображения или скрытия пароля с помощью значка глаза, оказывается, что когда мне удается это сделать, он меняет тип поля с текстового поля на FormControl, но они больше не показывают мне справочные сообщения, когда есть ошибка.

В коде есть 2 поля пароля, первое работает так, как я хочу, но без скрытия / отображения, а второе имеет значок, но, как я уже упоминал, оно не отображает сообщение.

Что меня поражает, так это то, что он правильно становится красным при возникновении ошибки.

Буду признателен, если вы поможете мне заставить его работать должным образом. Спасибо

import React, {useState} from 'react';
import Avatar from '@material-ui/core/Avatar';
import Button from '@material-ui/core/Button';
import CssBaseline from '@material-ui/core/CssBaseline';
import TextField from '@material-ui/core/TextField';
import Link from '@material-ui/core/Link';
import Grid from '@material-ui/core/Grid';
import Box from '@material-ui/core/Box';
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';
import InputAdornment from '@material-ui/core/InputAdornment';
import IconButton from '@material-ui/core/IconButton';
import FormControl from '@material-ui/core/FormControl';
import clsx from 'clsx';
import InputLabel from '@material-ui/core/InputLabel';
import * as yup from 'yup'
import { yupResolver } from '@hookform/resolvers';
import { useForm} from "react-hook-form";
import { OutlinedInput } from '@material-ui/core';

function Copyright() {
  return (
    <Typography variant="body2" color="textSecondary" align="center">
      {'Copyright © '}
      <Link color="inherit" href="https://material-ui.com/">
        Your Website
      </Link>{' '}
      {new Date().getFullYear()}
      {'.'}
    </Typography>
  );
}

const useStyles = makeStyles((theme) => ({
  paper: {
    marginTop: theme.spacing(8),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  },
  avatar: {
    margin: theme.spacing(1),
    backgroundColor: theme.palette.secondary.main,
  },
  margin: {
    margin: theme.spacing(1),
  },
  form: {
    width: '100%', // Fix IE 11 issue.
    marginTop: theme.spacing(3),
  },
  submit: {
    margin: theme.spacing(3, 0, 2),
  },
}));

const RegisterSchema = yup.object().shape({
    password: yup
    .string()
    .trim()
    .required('Requerido.') 
    .min(8, 'Contraseña es muy corta - Debe contener al menos 8 caracteres.')
    .max(15, 'Contraseña es muy larga - Debe contener máximo 15 caracteres.')
    .matches(/[a-zA-Z]/, 'Contraseña solo puede contener letras latinas.')
});

export default function SignUp() {
  
  const classes = useStyles();

  const [data, setData] = useState({
    password:'',
    showPassword: false,
  });
     
  const handleChange = (prop) => (event) => {
    setData({ ...data, [prop]: event.target.value });
  };

  const handleClickShowPassword = () => {
    setData({ ...data, showPassword: !data.showPassword });
  };

  const handleMouseDownPassword = (event) => {
    event.preventDefault();
  };

  const handleInputChange = (e) => {
    console.log(e.target.value);
    setData ({
      ...data,
      fullName: (data.firstName + ' ' + data.lastName),
      [e.target.name] : e.target.value,
    })
  }
  
  const {register, handleSubmit, errors} = useForm({
    resolver: yupResolver(RegisterSchema),
  });
  
  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <Container component="main" maxWidth="xs">
      <CssBaseline />
      <div className={classes.paper}>
        <Avatar className={classes.avatar}>
          <LockOutlinedIcon />
        </Avatar>
        <Typography component="h1" variant="h5">
          Registro
        </Typography>
        <form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
          <Grid container spacing={2}>
            {<Grid item xs={12}>
              <TextField
                variant="outlined"
                required
                fullWidth
                name="password"
                label="Contraseña"
                type="password"
                id="password"
                autoComplete="current-password"
                onChange={handleInputChange}
                inputRef={register}
                error ={!!errors.password}
                helperText={errors.password ? errors.password.message : ''}
                endAdornment={
                  <InputAdornment position="end">
                    <IconButton
                      aria-label="toggle password visibility"
                      onClick={handleClickShowPassword}
                      onMouseDown={handleMouseDownPassword}
                      edge="end"
                    >
                      {data.showPassword ? <Visibility /> : <VisibilityOff />}
                    </IconButton>
                  </InputAdornment>
                }
              />
            </Grid>}

          <FormControl 
            className={clsx(classes.margin, classes.textField)} 
            variant="outlined" 
            autoComplete="current-password"
            inputRef={register}
            error ={!!errors.password}
            helperText={errors.password ? errors.password.message : ''}
            name="password"
            type="password"
            id="password"
            fullWidth
            required
            >
            <InputLabel 
              htmlFor="outlined-adornment-password">
              Contraseña
            </InputLabel>
            <OutlinedInput
              id="outlined-adornment-password"
              type={data.showPassword ? 'text' : 'password'}
              value={data.password}
              onChange={handleChange('password')}
              endAdornment={
                <InputAdornment position="end">
                  <IconButton
                    aria-label="toggle password visibility"
                    onClick={handleClickShowPassword}
                    onMouseDown={handleMouseDownPassword}
                    edge="end"
                  >
                    {data.showPassword ? <Visibility /> : <VisibilityOff />}
                  </IconButton>
                </InputAdornment>
              }
              labelWidth={92}
            />
          </FormControl>
          </Grid>
          <Button
            type="submit"
            fullWidth
            variant="contained"
            color="primary"
            className={classes.submit}
          >
            Registrate
          </Button>
          <Grid container justify="flex-end">
            <Grid item>
              <Link href="#" variant="body2">
                ¿Tienes una cuenta? Ingresa
              </Link>
            </Grid>
          </Grid>
        </form>
      </div>
      <Box mt={5}>
        <Copyright />
      </Box>
    </Container>
  );
}

person Jorge Burguera    schedule 15.08.2020    source источник


Ответы (1)


В компоненте текстового поля вашего пароля

вы можете использовать это решение, попробуйте добавить какое-то состояние в свой компонент, которое определяет, хочет ли пользователь показать или скрыть пароль, и назовите его, например, showPassword

const [showPassword,setShow] = useState(false)

     <TextField
       variant="outlined"
       required
       fullWidth
       name="password"
       label="Contraseña"
       type={showPassword?"text":"password"}
    
     />

вызывать setShow (! showPassword), когда пользователь нажимает кнопку с глазом

Теперь, когда когда-либо setShow изменится на true, тип ввода будет текстовым и, таким образом, будет показан пароль.

person Mr.M    schedule 15.08.2020