Использование Ref внутри функционального компонента без сохранения состояния не работает в React JS

Я разрабатываю веб-приложение React JS. Я новичок в реакции js. Теперь я пытаюсь использовать Ref внутри функционального компонента без сохранения состояния для получения входного значения. Я следовал некоторым решениям, которые нашел в Интернете.

это мой компонент

const Login = (props) => {
  const {
    classes,
    width
  } = props;

  // Flip container to column on mobile screens.
  const panelDirection = width === 'xs' ? 'column' : 'row';

  let emailInput = null;
  let passwordInput = null;

  return (

    <Grid
      container
      direction="row"
      spacing={0}
      justify="center"
      alignItems="center"
      className={classes.background}
    >

      <Grid item sm={10} xs={12} className={scss.panel}>
      <form className="full-height" action="post">
        <Grid direction={panelDirection} container spacing={0}>
          <Grid
            item
            sm={6}
            xs={12}
          >
            <Card className={classNames(scss.card, classes['primary-card'])}>
              <CardContent className={scss['signup-content']}>
                <img src={logoImage} className={scss['signup-logo']} alt="logo" />
                <Typography variant="headline" component="h2" gutterBottom>
                  Web Portal
                </Typography>

              </CardContent>
              <CardActions>
                <Button fullWidth href="/register" color="secondary" variant="raised">Create an account</Button>
              </CardActions>
            </Card>
          </Grid>
          <Grid
            item
            sm={6}
            xs={12}
          >
            <Card className={scss.card}>
              <CardContent>
                <TextField
                  ref={(input) => { emailInput = input }}
                  label="Email Address"
                  fullWidth
                />
                <TextField
                  ref={(input) => { passwordInput = input }}
                  label="Password"
                  fullWidth
                  margin="normal"
                  type="password"
                />
              </CardContent>
              <CardActions className={scss['login-actions']}>
                <Button href="/login" color="primary" variant="raised">Login</Button>
                <Button href="/forgot-password">Forgot Password</Button>
              </CardActions>
            </Card>
          </Grid>
        </Grid>
        </form>
      </Grid>
    </Grid>

  );
};

Как видите, я использую ref для получения значений полей ввода электронной почты и пароля. Но, когда я бегу, он все еще дает мне эту ошибку.

Warning: Stateless function components cannot be given refs. Attempts to access this ref will fail.

Итак, как я могу исправить свой код? Как я могу правильно использовать Ref в функциональном компоненте без сохранения состояния?

Очевидно, я последовал этому, Как Я присоединяюсь к ссылке компонента без сохранения состояния в React?

Я также пытался использовать класс. Это дает мне ту же ошибку. Это версия класса моего компонента.

class Login extends React.Component {



  submitForm = e => {
    e.preventDefault();
  }

  constructor(props)
  {
    super(props);
    this.emailInput = React.createRef();
    this.passwordInput = React.createRef();
  }


  render () {
    const { classes, width } = this.props;

    // Flip container to column on mobile screens.
    const panelDirection = width === 'xs' ? 'column' : 'row';
    return (

    <Grid
      container
      direction="row"
      spacing={0}
      justify="center"
      alignItems="center"
      className={classes.background}
    >

      <Grid item sm={10} xs={12} className={scss.panel}>
      <form className="full-height" action="post" onSubmit={this.submitForm}>
        <Grid direction={panelDirection} container spacing={0}>
          <Grid
            item
            sm={6}
            xs={12}
          >
            <Card className={classNames(scss.card, classes['primary-card'])}>
              <CardContent className={scss['signup-content']}>
                <img src={logoImage} className={scss['signup-logo']} alt="logo" />
                <Typography variant="headline" component="h2" gutterBottom>
                  Web Portal
                </Typography>

              </CardContent>
              <CardActions>
                <Button fullWidth href="/register" color="secondary" variant="raised">Create an account</Button>
              </CardActions>
            </Card>
          </Grid>
          <Grid
            item
            sm={6}
            xs={12}
          >
            <Card className={scss.card}>
              <CardContent>
                <TextField
                  ref={this.emailInput}
                  label="Email Address"
                  fullWidth
                />
                <TextField
                  ref={this.passwordInput}
                  label="Password"
                  fullWidth
                  margin="normal"
                  type="password"
                />
              </CardContent>
              <CardActions className={scss['login-actions']}>
                <Button type="submit" color="primary" variant="raised">Login</Button>
                <Button href="/forgot-password">Forgot Password</Button>
              </CardActions>
            </Card>
          </Grid>
        </Grid>
        </form>
      </Grid>
    </Grid>
    )
  }

}

Login.propTypes = {
  classes: PropTypes.shape({}).isRequired,
  width: PropTypes.string.isRequired
};

export default compose(withWidth(), withStyles(themeStyles, { withTheme: true }))(Login);

person Wai Yan Hein    schedule 09.07.2018    source источник
comment
Вы пытались вместо этого превратить его в компонент класса?   -  person Tholle    schedule 09.07.2018
comment
Я использую функциональный компонент без сохранения состояния. Если я использую класс, это больше не функциональный компонент без состояния.   -  person Wai Yan Hein    schedule 09.07.2018
comment
Да, но зачем настаивать на использовании безгражданства, если фреймворк ясно говорит вам Stateless function components cannot be given refs.? Вы пробовали класс и посмотреть, если это проблема?   -  person Tholle    schedule 09.07.2018
comment
Итак, я просто использовал класс компонента.   -  person Wai Yan Hein    schedule 09.07.2018


Ответы (2)


Если вы настаиваете на использовании компонента без сохранения состояния (что для меня отлично), вы должны использовать обратный вызов для получения значения вашего ввода:

// Login.js
const Login = (props) => {
  const {
    classes,
    width,
    onChange, // <- get the callback here
  } = props;

  ...

  return (
    ...
            <TextField
              name="email"
              onChange={onChange}
              label="Email Address"
              fullWidth
            />
            <TextField
              name="password"
              onChange={onChange}
              label="Password"
              fullWidth
              margin="normal"
              type="password"
            />
  ...
);


// Somewhere to include Login
class LoginPage extends Component {
  ...
  handleInputChange({ target }) {
    ...
    console.log(target.name, target.value);
  }
  render (
    <Login onChange={this.handleInputChange} ... />
  )
}


// Or connect it to Redux
const mapDispatchToProps = dispatch => {
  const updateLoginInputValues = ({ target }) => dispatch(updateLoginInputValues(target.name, target.value)));
  return {
    onChange: updateLoginInputValues,
  }
};
const connectedLogin = connect(null, mapDispatchToProps)(Login

Единственная часть, которую вы можете улучшить, — это либо обработка значений с помощью управления состоянием, либо непосредственно с помощью React. Помимо этого, в какой-то момент вам нужно обратиться к состоянию, и вы не можете оставить все свои компоненты без состояния.

person Amin Paks    schedule 09.07.2018
comment
Это дает undefined для свойств параметра события. - person Wai Yan Hein; 09.07.2018
comment
Какой метод Redux или компонент класса? - person Amin Paks; 09.07.2018
comment
Просто убедитесь, что onChange() имеет правильную подпись. Не уверен, какой компонент вы используете, поэтому, возможно, обратный вызов возвращает значение напрямую, а не «цель». - person Amin Paks; 09.07.2018

Компонент без состояния означает, что он не содержит состояния, компонент обновляется только через реквизиты. Таким образом, вы можете использовать для этого контейнер class. вот решение...

import React, { Component } from "react";

class Login extends Component {
 constructor(props) {
  super(props);
  this.emailInput = React.createRef();
  this.passwordInput = React.createRef();
 }

 render() {
  const { classes, width } = this.props;

  // Flip container to column on mobile screens.
  const panelDirection = width === "xs" ? "column" : "row";

  return (
    <Grid container direction="row" spacing={0} justify="center" alignItems="center" className={classes.background}>
      <Grid item sm={10} xs={12} className={scss.panel}>
        <form className="full-height" action="post">
          <Grid direction={panelDirection} container spacing={0}>
            <Grid item sm={6} xs={12}>
              <Card className={classNames(scss.card, classes["primary-card"])}>
              <CardContent className={scss["signup-content"]}>
                <img src={logoImage} className={scss["signup-logo"]} alt="logo" />
                <Typography variant="headline" component="h2" gutterBottom>
                  Web Portal
                </Typography>
              </CardContent>
              <CardActions>
                <Button fullWidth href="/register" color="secondary" variant="raised">
                  Create an account
                </Button>
              </CardActions>
            </Card>
          </Grid>
          <Grid item sm={6} xs={12}>
            <Card className={scss.card}>
              <CardContent>
                <TextField ref={this.emailInput} label="Email Address" fullWidth />
                <TextField ref={this.passwordInput} label="Password" fullWidth margin="normal" type="password" />
              </CardContent>
              <CardActions className={scss["login-actions"]}>
                <Button href="/login" color="primary" variant="raised">
                  Login
                </Button>
                <Button href="/forgot-password">Forgot Password</Button>
              </CardActions>
            </Card>
          </Grid>
        </Grid>
      </form>
    </Grid>
  </Grid>
   )
 }
}

 export default Login;

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

this.emailInput.current.value и this.passwordInput.current.value

person Herat Patel    schedule 09.07.2018
comment
Я тоже использовал этот класс. Все равно выдает ту же ошибку. Пожалуйста, проверьте мой обновленный вопрос, чтобы увидеть классовую версию моего кода. - person Wai Yan Hein; 09.07.2018
comment
какую версию реакции js вы используете? - person Herat Patel; 10.07.2018