Использование 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);
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. Помимо этого вам нужно обратиться к состоянию в какой-то момент, и вы не можете оставить все свои компоненты без состояния.
Компонент без состояния означает, что он не содержит состояния, компонент обновляется только через реквизиты. Так что вы можете использовать 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