В прошлой теме рассматривалось, как обновлять значение при вводе с помощью обработчика события change. Но есть и другой способ получения введенных данных, который заключается в использовании атрибута ref.
Атрибут ref может применяться к любому элементу веб-страницы. После установки атрибута в коде React мы сможем ссылать на этот элемент. Например:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Формы в React</title> </head> <body> <div id="app"></div> <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel"> class UserForm extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.nameField = React.createRef(); } handleSubmit(e) { e.preventDefault(); console.log(this.nameField); var name = this.nameField.current.value; alert("Имя: " + name); } render() { return <form onSubmit={this.handleSubmit}> <input ref={this.nameField} /> <input type="submit" value="Отправить" /> </form>; } } ReactDOM.createRoot( document.getElementById("app") ) .render( <UserForm /> ); </script> </body> </html>
Для создания ссылок ref
применяется функция React.createRef(). В данном случае это происходит в конструкторе:
this.nameField = React.createRef();
Затем созданную ссылку можно прикрепить к какому-нибудь элементу на html-странице. Для этого применяется применяется атрибут ref
,
которому в фигурных скобках передается ссылка.
<input ref={this.nameField} />
Далее в коде мы сможем ссылаться на этот элемент, в том числе получать его значения, с помощью выражения this.nameField.current.
Единственный минус в этом случае, то что мы не можем установить значение по умолчанию с помощью стандартного атрибута value: при использовании атрибута value опять же придется задавать обработчик события change, как в прошлой теме. Альтернативой данному подходу служит применение специального атрибута defaultValue, который задает для поля ввода значение по умолчанию:
render() { return <form onSubmit={this.handleSubmit}> <input defaultValue="Tom" ref={this.nameField} /> <input type="submit" value="Отправить" /> </form>; }
Возьмем форму из прошлой темы и разделим ее на компоненты с применением атрибута ref:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Формы в React</title> </head> <body> <div id="app"></div> <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel"> class NameField extends React.Component { constructor(props) { super(props); var isValid = this.validate(props.value); this.state = {value: props.value, valid: isValid}; this.onChange = this.onChange.bind(this); } validate(val){ return val.length>2; } onChange(e) { var val = e.target.value; var isValid = this.validate(val); this.setState({value: val, valid: isValid}); } render() { var color = this.state.valid===true?"green":"red"; return <p> <label>Имя:</label><br /> <input type="text" value={this.state.value} onChange={this.onChange} style={{borderColor:color}} /> </p>; } } class AgeField extends React.Component { constructor(props) { super(props); var isValid = this.validate(props.value); this.state = {value: props.value, valid: isValid}; this.onChange = this.onChange.bind(this); } validate(val){ return val>=0; } onChange(e) { var val = e.target.value; var isValid = this.validate(val); this.setState({value: val, valid: isValid}); } render() { var color = this.state.valid===true?"green":"red"; return <p> <label>Возраст:</label><br /> <input type="number" value={this.state.value} onChange={this.onChange} style={{borderColor:color}} /> </p>; } } class UserForm extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.nameField = React.createRef(); this.ageField = React.createRef(); } handleSubmit(e) { e.preventDefault(); var name = this.nameField.current.state.value; var age = this.ageField.current.state.value; if(this.nameField.current.state.valid && this.ageField.current.state.valid){ alert(`Имя: ${name} Возраст: ${age}`); } } render() { return ( <form onSubmit={this.handleSubmit}> <NameField value="" ref={this.nameField} /> <AgeField value="5" ref={this.ageField} /> <input type="submit" value="Отправить" /> </form> ); } } ReactDOM.createRoot( document.getElementById("app") ) .render( <UserForm /> ); </script> </body> </html>
Вначале в конструкторе компонента UserForm создаем две ссылки:
this.nameField = React.createRef(); this.ageField = React.createRef();
Затем для обращения к вложенным компонентам у каждого устанавливается атрибут ref:
<NameField value="" ref={this.nameField} /> <AgeField value="5" ref={this.ageField} />
И в дальнейшем по значению атрибута мы можем ссылаться на эти компоненты, в том числе получать их состояние:
handleSubmit(e) { e.preventDefault(); var name = this.nameField.current.state.value; var age = this.ageField.current.state.value; if(this.nameField.current.state.valid && this.ageField.current.state.valid){ alert(`Имя: ${name} Возраст: ${age}`); } }