在React JS中无法在无状态功能组件中使用Ref

时间:2018-07-09 10:34:33

标签: reactjs react-component

我正在开发一个React JS Web应用程序。我是新来的反应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?

很明显,我遵循了这个How can I attach to a stateless component's ref in 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);

2 个答案:

答案 0 :(得分:1)

缺少状态的组件意味着它不包含状态,该组件仅通过道具进行更新。因此,您可以使用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.valuethis.passwordInput.current.value

答案 1 :(得分:0)

如果您坚持使用无状态组件(对我来说这很棒),则应该使用回调来检索输入值:

// 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来处理。除此之外,您还需要在某个时候解决状态问题,并且不能使所有组件保持无状态。