Refs

Последнее обновление: 01.04.2022

В прошлой теме рассматривалось, как обновлять значение при вводе с помощью обработчика события 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.

Ref в React

Единственный минус в этом случае, то что мы не можем установить значение по умолчанию с помощью стандартного атрибута 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}`);
	}
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850